Skip to content

feat(config): config-driven tracker backend via rig.yaml task: block#7

Merged
alex-mextner merged 2 commits into
mainfrom
feat/config-driven-tracker-backend
Jun 18, 2026
Merged

feat(config): config-driven tracker backend via rig.yaml task: block#7
alex-mextner merged 2 commits into
mainfrom
feat/config-driven-tracker-backend

Conversation

@alex-mextner

Copy link
Copy Markdown
Owner

What

Wires task-cli's tracker backend selection to be config-driven from the repo's rig.yaml (CTO decision #4136.4: "for hyperide a LOCAL rig.yaml setting -> Linear, default -> GitHub Issues").

task-cli now reads its per-repo tracker backend from a flat task: block in the repo's committed rig.yaml — the single source of truth for the agent toolchain:

# rig.yaml (repo root)
task:
  backend: linear      # or github-issues (the default for every other repo)
  team: HYP            # -> linear.team
  # project: ""        # -> linear.project
  # repo: owner/name   # -> github.repo

Design

  • DEFAULT = GitHub Issues. No task: block (or no rig.yaml) -> clean fall-through to github-issues.
  • Cascade (later wins): defaults -> global -> rig.yaml task: -> task.yaml -> --config. A repo keeping a native task.yaml is untouched (it still wins over rig.yaml).
  • Flat block translated to task-cli's own shape: team/project/repo are shorthands; full github:/linear:/enforce:/classify:/session:/projects: sections may be nested verbatim and deep-merge with the shorthands (order-independent; a true leaf collision is a hard error).
  • Forward-compatible with rig-cli (rig.yaml is a foreign file rig owns/evolves):
    • a parse error or non-mapping root falls through to the github default (logged, never fatal);
    • an unknown sub-key under task: is warned-and-ignored, not a crash;
    • version is not passed through (rig.yaml has its own top-level version);
    • validate() type-guards a non-string backend into a clean ConfigError instead of an unhashable-type TypeError on foreign input.

Tests

tests/test_config.py: default=github, rig.yaml override=linear, missing/inert/broken/non-mapping rig.yaml=github, flat+nested merge for both linear and github (both orders), leaf-conflict rejected, unknown-key and stray version tolerated, malformed backend -> clean error. tests/smoke.sh covers the end-to-end rig.yaml -> linear/HYP selection. Full suite: 223 passing.

Reviewed across models before commit (review-before-commit gate); GLM seat was throttled (429) throughout, so the diff was reviewed on the Opus correctness seat across three rounds — each round's findings fixed (data-loss on flat+nested mix, forward-compat for unknown keys, foreign-file tolerance, non-string backend guard).

🤖 Generated with Claude Code

…lt github)

task-cli now reads its per-repo tracker backend from the repo's committed
rig.yaml — the single source of truth for the agent toolchain — via a flat
`task:` block (CTO decision #4136.4: hyperide -> Linear/HYP, every other repo
-> GitHub Issues by default). The cascade is defaults -> global -> rig.yaml
task: -> task.yaml -> --config, so a repo keeping a native task.yaml is
untouched, and a repo with only a rig.yaml task: block needs no task.yaml.

The block is flat: `team`/`project`/`repo` are shorthands translated onto
task-cli's own shape; full sections may be nested verbatim and deep-merge with
the shorthands (order-independent; a true leaf collision is a hard error).

rig.yaml is a FOREIGN file owned/evolved by rig-cli, so the read is
forward-compatible: a parse error or non-mapping root falls through to the
github default (logged, never fatal), and an unknown sub-key under task: is
warned-and-ignored rather than crashing every `task` command. `version` is not
passed through (rig.yaml has its own top-level version). validate() now
type-guards a non-string backend into a clean ConfigError instead of an
unhashable-type TypeError on foreign input.

Tests: default=github, rig.yaml override=linear, missing/inert/broken/non-mapping
rig.yaml=github, flat+nested merge for both linear and github (both orders),
leaf-conflict rejected, unknown-key and stray version tolerated, malformed
backend value -> clean error. Smoke covers the rig.yaml->linear/HYP path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46143068af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tasklib/config.py
…ig-managed repo

The rig.yaml load only caught ConfigError, so in a repo that merely CONTAINS a
rig.yaml, a missing PyYAML (the installer can continue without it, promising
built-in defaults) made `task list` traceback with ModuleNotFoundError from the
lazy `import yaml` in _load_yaml instead of ignoring the unreadable foreign file.

Catch ModuleNotFoundError for the yaml import in that block and treat it the same
as the unreadable/invalid rig.yaml path: warn-and-ignore, fall through to the
built-in GitHub-Issues default. Scoped by exc.name (yaml / _yaml / yaml.*) only,
never the message, so an unrelated missing module whose name merely contains
"yaml" (e.g. yaml_processor) still surfaces; ModuleNotFoundError (not the broader
ImportError) so a circular/broken-init error is not swallowed. The tolerance stays
rig.yaml-only — task-cli's own task.yaml/global remain fail-closed. Shared the
warn-and-ignore via _ignore_rig and corrected the message ("not loaded" vs
"unreadable" — a missing-PyYAML file is readable, just unparsed).

Regression tests: rig.yaml present + yaml stubbed out of sys.modules -> backend
falls back to github default, no exception, WARN logged; yaml submodule
(_yaml / yaml.cyaml) missing -> same fall-through; an unrelated/substring-collision
ModuleNotFoundError (yaml_processor) still propagates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alex-mextner alex-mextner merged commit 8e93bc4 into main Jun 18, 2026
4 checks passed
@alex-mextner alex-mextner deleted the feat/config-driven-tracker-backend branch June 18, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant