Skip to content

[DEV-184] Per-job agent harness, model, and effort for automations, estimations, and conflict resolution - #286

Merged
danii1 merged 8 commits into
mainfrom
feature/dev-184
Nov 13, 2026
Merged

danii1 merged 8 commits into
mainfrom
feature/dev-184

Conversation

@danii1

@danii1 danii1 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Why

Task DEV-184: per-job agent harness, model, and effort selection.

Every worker job used the workspace/repo AGENT_HARNESS, AGENT_MODEL, and AGENT_EFFORT, so cheap, mechanical work (triage, estimation, merge-conflict resolution) ran on the same frontier model as feature work. This adds optional per-job overrides so e.g. scheduled automations or conflict resolution can run on Sonnet while tracker tasks stay on Opus.

What changed

  • agent/selection.ts (new): AgentSelection, parseAgentSelection (validates one harness name against the registry, canonicalizes aliases, reuses parseAgentEffort, optional key prefix), applyAgentSelectionEnv, pinnedHarnessChildEnv, and the uninstalled-pin warning.
  • [[automations]] / [[estimations]]: optional harness, model, effort. Applied in the context env and again in the run env. Team-scoped estimations (buildTeamWorkspaceContextEnv) apply it too.
  • Conflict resolution: new [workspace].conflict_resolution_harness / _model / _effort, applied to automatic resolution on GitHub (fleet-events.ts) and GitLab (gitlab-fleet-events.ts). It's read at run time, so live reload applies it.
  • Semantics
    • model without harness is written to the primary harness's own <HARNESS>_MODEL (e.g. CLAUDE_CODE_MODEL). So model = "sonnet" alone works, failover stays on, and a fallback harness keeps its own default model. A pinned model also outranks an inherited <HARNESS>_MODEL.
    • harness pins one agent and opts that job out of the failover chain. A pinned automation fails that run on a usage limit. A pinned conflict resolution (runWithFailover({ harnessPin })) spawns once and defers. When the pin changes the harness, the inherited AGENT_MODEL / AGENT_EFFORT / AGENT_CLI_PATH (and the CLAUDE_CLI_PATH fallback) are dropped.
    • effort is harness-neutral and applies with or without a pin.
    • Precedence: job field > team/repo env > workspace env > harness default.
  • The standalone dashboard manual run marks its child with DEVINTERN_SKIP_PROJECT_ENV, so dotenv can't re-add the keys the selection dropped.
  • Scheduled-job context resolvers moved to workspace/schedule-context.ts (keeps workspace-worker.ts under max-lines). They're re-exported from workspace-worker.ts.
  • agent-harness: claude is now an alias for claude-code (e.g. AGENT_HARNESS=claude,codex,grok). Pinning the deprecated gemini alias on a job prints its deprecation warning when the config loads, since the child process only ever sees the real name.
  • Docs: docs/code/worker.md ("Choosing the agent per schedule", with a model-only example) and docs/code/workspaces.md (entry bullet, plus a conflict resolution "Choosing the agent" paragraph).

Example

[workspace]
conflict_resolution_model = "sonnet"

[[automations]]
id = "dependency-bump"
enabled = true
interval = "1d"
model = "sonnet"
prompt = "Upgrade one outdated patch-level dependency and run the tests."

Tradeoffs

  • harness is a single name, not a chain. Pinning opts out of failover, so a usage limit on a pinned agent fails (automation) or defers (conflict resolution) instead of switching agents. Leave harness unset to keep failover.
  • model is never validated across harnesses.
  • A manual devintern resolve-conflicts <pr-url> uses the normal environment, not the conflict-resolution setting.
  • Out of scope: per-job failover chains, showing the selection on the dashboard, and per-ticket selection for tracker and review runs (that already exists via task-description preferences).

Blast radius

All new fields are optional and additive. Configs that set none of them behave as before. runWithFailover and the env builders take new optional parameters; existing callers are unchanged. Editing a model or harness doesn't reset an automation's schedule cursor.

Verification

  • bun run typecheck, bun run lint (lefthook): pass.
  • bun run test (packages/code, ambient AGENT_* unset): 2893 pass, 0 fail.
  • New tests cover model-only scoping (resolves on the primary, not on a fallback), conflict-agent parsing and validation, pinned vs. unpinned runWithFailover, fleet conflict wiring under live mutation, and the failover probe for model-only entries.

🤖 Generated with Claude Code

1. [MEDIUM] bug in automation/acquirer.ts: a pinned harness skipped the
   whole failover overlay, which was also the only thing setting
   DEVINTERN_WORKER_CHILD=1. The pinned CLI child therefore stopped being a
   worker child, so a usage-limit abort wrote no hint and exited 0 (falling
   through to one-shot success handling) instead of exiting 75. Keep the
   worker-child marker on pinned children and drop any inherited hint path;
   the existing !options.harnessPin guard already prevents re-spawning on
   another harness.

2. [MEDIUM] testing: add spawnAutomationProcess coverage for pinned runs
   (stub child exits 75 with a started failover) asserting the pinned
   AGENT_HARNESS, the worker-child marker, no leaked hint path, and no
   failover, plus the estimation variant and an unpinned failover control.

Iteration 2 fixes:

3. [MEDIUM] bug in agent/selection.ts: an entry that set model/effort without
   a harness kept workspace failover, and the failover overlay only rewrote
   AGENT_HARNESS, so a harness-specific model leaked onto whichever fallback
   harness ran. applyAgentSelectionEnv now writes model/effort only when the
   entry also pins a harness, so a model-only entry leaves the inherited value
   untouched and can never reach a different harness.

4. [MEDIUM] bug in automation/acquirer.ts: a pinned harness left the
   inherited AGENT_CLI_PATH in place, so the child resolved the workspace
   primary's binary for the pinned harness. applyAgentSelectionEnv now drops
   AGENT_CLI_PATH when the pin differs from the env's primary harness (keeping
   it for a primary pin), and pinAutomationEnv applies the same guard for
   direct callers. Shared via a new primaryHarnessName helper.

5. [testing] add unit and spawnAutomationProcess integration coverage for
   model-only entries (no leak to primary or fallback) and for AGENT_CLI_PATH
   being dropped on a non-primary pin but kept on a primary pin; update the
   worker/workspaces docs to state the model/effort-require-harness contract.

Iteration 3 fixes:

6. [HIGH] bug in agent/selection.ts and automation/acquirer.ts: dropping only
   AGENT_CLI_PATH on a non-primary pin left the resolver's CLAUDE_CLI_PATH
   backward-compat fallback in place. resolveEnvHarnessPath (resolver.ts) uses
   CLAUDE_CLI_PATH for ANY harness, so a codex pin still resolved to the claude
   binary. applyAgentSelectionEnv and pinAutomationEnv now share a
   dropForeignHarnessCliPaths helper that also drops CLAUDE_CLI_PATH for a
   non-claude pin (kept when pinning claude-code).

7. [MEDIUM] bug in agent/selection.ts: an entry that pinned a different
   harness but omitted model/effort inherited the env primary's
   harness-specific AGENT_MODEL/AGENT_EFFORT. When the pin changes the harness
   those inherited values are now dropped unless the entry sets its own,
   mirroring the failover-case reasoning (same pin keeps them).

8. [testing] regression coverage: unit tests that a non-claude pin resolves its
   own binary rather than the inherited CLAUDE_CLI_PATH and that inherited
   model/effort are dropped/kept by whether the pin changes harness, plus
   spawnAutomationProcess integration tests for CLAUDE_CLI_PATH dropped on a
   non-claude pin, kept on a claude pin, and the inherited model dropped on a
   harness-changing pin. Docs updated.

Iteration 4 fixes:

9. [MEDIUM] bug in automation/manual.ts: the standalone dashboard's 'Run now'
   composed context.env from process.env without pinning
   DEVINTERN_WORKER_SUBPROCESS, so the spawned CLI child ran loadEnvironment()
   and dotenv re-populated the AGENT_CLI_PATH/AGENT_MODEL that the entry's
   harness pin had deliberately dropped (the cross-harness leak this PR fixes
   on the scheduled/estimation paths). Pin the worker-subprocess marker in the
   manual context so the child skips the checkout's .env; end-to-end test
   composes the real automationRunEnv child env, runs the real loadEnvironment
   in a subprocess, and asserts the dropped keys stay dropped (and would be
   restored without the marker).

10. [MEDIUM] bug in agent/selection.ts: parseAgentSelection validated a pinned
    harness only against the registry, so an entry pinned to a
    registered-but-uninstalled harness (or a wrong <HARNESS>_CLI_PATH) failed
    every occurrence silently with no failover. Add warnUninstalledHarnessPins
    and call it at worker startup (applyWorkspaceEnv) and on config reload
    (validateReloadedWorkspaceConfig), mirroring the AGENT_HARNESS chain's
    installability warnings; unit tests cover the missing-CLI warning and the
    AGENT_CLI_PATH rules for primary vs non-primary pins. Docs updated.

Iteration 5 fixes:

11. [MEDIUM] bug in automation/manual.ts: iteration 4 pinned the broad
    DEVINTERN_WORKER_SUBPROCESS marker on the standalone dashboard manual
    spawn purely to skip dotenv, but isWorkerSubprocess() also switches
    resolveRuntimeStateDir() from the project .devintern-code to the
    workspace state dir (~/.devintern/state/code). An automated (systemd/CI)
    dashboard-spawned child then read the wrong .auth-session.json in
    loadSupabaseConfig() (index.ts) and could fail the automation-license
    gate. Add a narrow DEVINTERN_SKIP_PROJECT_ENV marker and a
    shouldSkipProjectEnv() helper that loadEnvironment() consults; manual.ts
    sets the narrow marker instead, so the child skips the checkout .env
    while its runtime state and auth session still resolve to the project
    config dir. Scheduled runs keep the worker marker (and workspace state).

12. [testing] automation-manual.test.ts: assert the narrow marker is set and
    add a regression test that runs the real resolveRuntimeStateDir /
    loadSupabaseConfig in a subprocess and asserts the manual child stays
    project-scoped, with the worker marker control showing the workspace-dir
    relocation the fix avoids. Make the dotenv-leak control hermetic against
    an inherited worker marker.
@danii1 danii1 added the devintern-authored Pull request written by DevIntern working its own backlog label Oct 16, 2026
@danii1

danii1 commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Artifacts & verification

Run: 763 · Commit: 8a437820f79ceb985bddcc65066ee764c45f6d8d

Change explanation

Produced by pr-explainer-narrative, execution 1 at 8a437820f79ceb985bddcc65066ee764c45f6d8d.

Per-automation and per-estimation agent harness, model, and effort selection (DEV-184)

No PR template is present in this repository (.github/ contains only readme/ and workflows/), so the sections below are free-form rather than template-driven.

Why this change is needed

The task states the motivation directly: today the agent is chosen once per workspace/repo. AGENT_HARNESS, AGENT_MODEL, and AGENT_EFFORT come from the environment layers, and every run shares that choice. Workspace [[automations]] and [[estimations]] entries have no way to override it, so a cheap daily triage job and a heavyweight release job are forced onto the same model and effort. Operators running mixed workloads want to set harness/model/effort per schedule instead of running separate workers or duplicating env files.

What changed

Grouped by purpose:

New configuration surface. [[automations]] and [[estimations]] entries accept optional harness (one agent), model, and effort. Parsing and validation live in the new packages/code/src/lib/agent/selection.ts (parseAgentSelection), called from both config parsers. An unknown harness or an effort outside low | medium | high fails config validation with a message naming the entry id and field; it does not silently fall back. A harness chain ("codex,grok") is rejected because an entry names one agent. Validation runs through parseWorkspaceConfig without starting the worker.

Precedence and env composition. applyAgentSelectionEnv overlays only the fields the entry set onto the composed child env, so omitted fields fall through to team/repo env, then workspace env, then harness default (the precedence the task specifies). It is wired last in buildRepoEnv, buildTeamTaskEnv, buildWorkspaceContextEnv, automationRunEnv, and estimationRunEnv. The task intended model/effort to be harness-specific, so the implementation applies them only when the entry also pins a harness; a model- or effort-only entry keeps normal failover and the inherited value. When a pin changes the harness away from the env primary, the inherited AGENT_MODEL/AGENT_EFFORT and the primary's AGENT_CLI_PATH (plus the resolver's CLAUDE_CLI_PATH fallback for a non-claude-code pin) are dropped so the pinned agent resolves its own binary and defaults.

Failover opt-out. A pinned harness opts the entry out of the workspace AGENT_HARNESS failover chain: spawnAutomationProcess passes a harnessPin, pinAutomationEnv pins the child to exactly that harness and skips the failover overlay, and usage-limit exits are not re-routed. Entries without harness keep normal failover. The pin also survives the worker-child env marker so a usage-limit abort still signals the parent.

Startup/reload visibility. Because a pin disables failover, warnUninstalledHarnessPins warns (naming the entry) when a pinned harness is registered but its CLI is not installed or its <HARNESS>_CLI_PATH points at a missing executable. It runs at worker startup and on config reload.

Manual dashboard path isolation. The standalone dashboard's manual spawn applies the same selection but must not let the child's dotenv reload re-populate the dropped keys. This introduced a narrow DEVINTERN_SKIP_PROJECT_ENV marker (shouldSkipProjectEnv) so bootstrap.ts skips .devintern-code/.env without treating the child as a worker subprocess, keeping runtime state and the license/auth session in the project config dir.

Docs. docs/code/workspaces.md and docs/code/worker.md document the fields, valid values, precedence, and the failover opt-out.

Validation actually performed

Grounded in the pipeline step results provided:

  • The __verify-1 artifact states that all DEV-184 acceptance criteria are met, that the 19 new tests pass, and that typecheck, lint, and format:check are clean.
  • The same artifact records 3 suite failures and characterizes them as pre-existing environment pollution (AGENT_MODEL, DEVINTERN_WORKER_SUBPROCESS=1, and an offline network test), reproduced as passing once those env vars are unset.
  • auto-review states the core selection/pin behavior was verified end-to-end with new tests that launch a real stub child, and that the full automation/agent/workspace test set passes ("ran-it").
  • The new test files in the diff cover precedence, validation errors, unsupported-effort acceptance-at-parse, estimation overrides, failover opt-out at spawn, CLI-path/model drop rules, and the manual-path skip-marker behavior. __verify-1 lists one residual coverage gap: the in-flight vs reload semantics of a pin are not directly exercised.

Observed vs inferred:

  • Observed: the artifact claims above are what the pipeline recorded. I did not independently run the suite in this step, so those results are reported from the artifacts, not re-confirmed here.
  • Inference: the auto-review feedback (feedback-5) still describes the manual-path marker as WORKER_SUBPROCESS_ENV, while the final diff and current config-dir.ts/manual.ts use the narrow DEVINTERN_SKIP_PROJECT_ENV. Treat the diff as authoritative; the review text appears to predate the repair. The auto-review run ended success: false with a medium-confidence item on the manual path plus a note about latent team-path code, so review did not approve as-is.

Material risks

  • Manual-path marker change: adding a skip gate to bootstrap.ts changes behavior for the standalone dashboard's manual runs. The diff includes a test asserting runtime state and the auth session stay in .devintern-code under the narrow marker, but the original review concern (reading the wrong .auth-session.json) was rated "pointed," not demonstrated at runtime.
  • Precedence edge behavior: when an entry pins a harness different from the env primary without setting model/effort, the inherited values are dropped. That is intentional (avoid cross-harness leaks) but is a behavior change users may not expect.
  • Unvalidated model strings: model is intentionally not validated cross-harness, so a bad model fails at agent runtime, not config load.
  • Reload semantics: the task requires overrides to apply to subsequent occurrences while in-flight runs keep their selection. applyAgentSelectionEnv operates on freshly copied per-run env objects and warnUninstalledHarnessPins runs on reload, but the in-flight half is not directly tested.
  • Team path: [redacted] re-applies the selection after the team layer; the auto-review notes it as latent/unwired and not exercised.

Where reviewers should focus

The smallest set of files and behaviors that carry the risk:

  • packages/code/src/lib/agent/selection.ts — validation, precedence, drop rules, warning probe.
  • packages/code/src/lib/automation/acquirer.ts — pinAutomationEnv/spawnAutomationProcess failover opt-out.
  • packages/code/src/lib/config/config-dir.ts and packages/code/src/lib/cli/bootstrap.ts — the new skip gate's blast radius.
  • packages/code/src/lib/automation/manual.ts — the manual path that consumes the skip marker.
  • packages/code/src/lib/workspace/env.ts — where the selection is overlaid relative to env layers.

Visual explanation

Produced by pr-explainer-visual, execution 1 at 8a437820f79ceb985bddcc65066ee764c45f6d8d.

Show artifact

Summary

[[automations]] and [[estimations]] entries in workspace.toml now accept optional harness, model, and effort fields that apply only to that entry's runs; every other run keeps the existing workspace/repo/team AGENT_HARNESS/AGENT_MODEL/AGENT_EFFORT. This lets an operator run a cheap model on a simple schedule and a frontier model on a complex one without separate workers or duplicated env files. Unknown harness names or invalid effort values fail config parsing with a message naming the entry id and field rather than falling back silently.

Evidence

The change is one new module (packages/code/src/lib/agent/selection.ts) wired through parse, env composition, and spawn:

workspace.toml entry  { harness?, model?, effort? }
        |
        v  parseAgentSelection()                    (config load / live reload)
   harness must be ONE known name; effort in {low, medium, high}
   else -> error naming entry id + field
        |
        v  selection stored on AutomationConfig / EstimationConfig
        |
   occurrence -> compose env layers (team/repo > workspace > harness default)
        |
        v  applyAgentSelectionEnv()                  (last overlay, on a fresh copy)
   harness set   -> AGENT_HARNESS = harness
                    drop foreign AGENT_CLI_PATH / CLAUDE_CLI_PATH
                    model/effort written ONLY when harness is also set
                    inherited model/effort dropped when the harness changes
        |
        v  spawnAutomationProcess(harnessPin: harness)
   pinned  -> opts out of workspace AGENT_HARNESS failover
   no pin  -> normal failover chain, selection untouched

Files added/changed: agent/selection.ts (new), automation/{config,estimation-config,acquirer,estimation-acquirer,manual}.ts, workspace/{env,workspace-worker}.ts, cli/bootstrap.ts, config/config-dir.ts, docs worker.md and workspaces.md; tests in agent-selection.test.ts (new), automation-acquirer.test.ts, automation-manual.test.ts, workspace-worker.test.ts.

Validation, as reported by the pipeline evidence (not independently re-run here):

  • __verify-1 states the implementation satisfies all DEV-184 acceptance criteria, the 19 new tests pass, and typecheck/lint/format:check are clean. It attributes 3 suite failures to pre-existing environment pollution (AGENT_MODEL, DEVINTERN_WORKER_SUBPROCESS=1, and an offline network test), which it reproduced as passing once those env vars were unset.
  • auto-review did not pass: 5 iterations, success: false. Its medium concern was that the standalone manual-run path set WORKER_SUBPROCESS_ENV, which also relocates runtime state and the auth session to the workspace state dir. The final diff instead introduces a narrow DEVINTERN_SKIP_PROJECT_ENV marker and adds a test asserting runtime state and auth stay in the project config dir; no evidence shows a subsequent auto-review re-run or pass.

Before/after execution results were not captured in the supplied evidence; the only side-by-side is test source (a pinned child vs. a deliberately "leaky" control), not recorded command output.

Merge Danger

Reversible: a plain revert of these files; no schema change, migration, or persisted data, and existing workspace.toml files that set none of the new fields load unchanged (empty selection is a documented no-op).

Blast radius: the changed env builders (buildRepoEnv, buildTeamTaskEnv, buildWorkspaceContextEnv) and spawn path (spawnAutomationProcess/pinAutomationEnv) sit under every worker job, so all runs traverse the new code even when unaffected — but each mutates only a freshly copied per-occurrence env object, so untargeted runs are unchanged. Two behaviors carry the real risk: (1) a pinned harness opts the entry out of workspace failover, so a pin to a registered-but-uninstalled harness fails all of that entry's runs — warnUninstalledHarnessPins surfaces this at startup and reload, but it is a warning, not a block; (2) the manual-run path now sets the narrow skip-env marker so dotenv cannot repopulate the dropped CLI path/model, which changes that path's child environment.

Shipability: no staged rollout is strictly required because entries without the new fields behave exactly as before and validation is fail-closed at parse time. The residual risk is concentrated in the failover opt-out and the manual skip-env marker; both have targeted tests, but the auto-review did not reach a passing state, so a staged rollout or a second review is the prudent call before broad release.

Verification report

Produced by __verify-1, execution 1 at c547fd19474f345109ff4c6aaec6a5c34bfe6931.

Show artifact
{
  "summary": "Implementation satisfies all DEV-184 acceptance criteria. New `packages/code/src/lib/agent/selection.ts` parses/validates optional `harness`/`model`/`effort` on `[[automations]]` and `[[estimations]]`; the source is compiled by both config parsers; the selection is overlaid last in `buildRepoEnv`, `buildTeamTaskEnv`, `buildWorkspaceContextEnv`, `automationRunEnv` and `estimationRunEnv`; a pinned harness opts out of workspace failover via `harnessPin`. `parseAgentEffort` enforces low/medium/high and `getHarness` enforces known single names with id+field in the message. Untargeted runs are byte-for-byte unchanged because `applyAgentSelectionEnv` is a no-op for empty selections. Docs updated in the two required files. The 19 new tests pass and `typecheck`/`lint`/`format:check` are clean; the 3 suite failures are pre-existing environment pollution (AGENT_MODEL, DEVINTERN_WORKER_SUBPROCESS=1, and an offline network test), reproduced as passing once those env vars are unset. Residual gaps are test coverage of the failover-opt-out and a usage-limit status nuance, not unmet requirements.",
  "items": [
    {
      "priority": "info",
      "confidence": "medium",
      "category": "testing",
      "file": "packages/code/src/lib/automation/acquirer.ts",
      "line": "806",
      "issue": "The core new behavior of `harness` — opting the entry out of the workspace failover chain (harnessPin skips `failover.childEnv`) and in-flight runs keeping their original selection — has no test. Only env composition is asserted.",
      "evidence": "rg -n \"harnessPin\" shows matches only under packages/code/src (acquirer.ts, estimation-acquirer.ts); no test file references it. `bun test tests/agent-selection.test.ts` = 19 pass, but none exercise pinAutomationEnv/failover.",
      "suggestion": "Add a test that starts a fake WorkerFailover, spawns a pinned-harness automation, and asserts the child env keeps the pinned AGENT_HARNESS and never re-pins to the active chain entry; add a reload test that a changed entry selection applies to the next occurrence while the in-flight run's env is unchanged."
    },
    {
      "priority": "low",
      "confidence": "medium",
      "category": "bug",
      "file": "packages/code/src/lib/automation/acquirer.ts",
      "line": "810",
      "issue": "For a pinned harness, `pinAutomationEnv` returns early and never sets `DEVINTERN_WORKER_CHILD`, so the child is not treated as a worker child. On an agent usage limit the child takes the one-shot path and exits 0 (see run.ts:205/298 `isWorkerChild()`), so the occurrence is recorded as a successful run rather than deferred/failed.",
      "evidence": "acquirer.ts:806-810 early-returns without the `[WORKER_CHILD_ENV]: \"1\"` that failover.childEnv sets (failover.ts:161); usage-limit handling at packages/code/src/lib/cli/run.ts:205 and :298 gates on isWorkerChild().",
      "suggestion": "Either set the child marker alongside the pinned harness so usage limits still defer cleanly, or document explicitly that a pinned harness treats usage limits as end-of-run and retries on the next occurrence."
    },
    {
      "priority": "low",
      "confidence": "medium",
      "category": "testing",
      "file": "packages/code/tests/agent-selection.test.ts",
      "line": "88",
      "issue": "The acceptance criterion 'tests cover unsupported-effort handling' is only covered at parse time: the new test asserts that effort on `cursor` parses without error, not that the run proceeds with a warning and does not fail.",
      "evidence": "agent-selection.test.ts:88-98 only calls parseAgentSelection; the runtime warning path is covered by pre-existing packages/agent-harness/tests/effort.test.ts:71-100 (warnEffortUnsupported), not by this change.",
      "suggestion": "Add a test asserting an entry with `harness = \"cursor\"`, `effort = \"low\"` spawns successfully while emitting the unsupported-effort warning, to lock the run-does-not-fail contract end to end."
    },
    {
      "priority": "low",
      "confidence": "low",
      "category": "code-quality",
      "file": "packages/code/src/lib/agent/selection.ts",
      "line": "126",
      "issue": "Pinning `AGENT_HARNESS` to a single canonical name does not prevent a workspace-wide `AGENT_CLI_PATH` from resolving the executable path, so a pinned harness could still invoke a different harness's binary. This mirrors existing failover behavior rather than introducing it, but it weakens the 'uses exactly the agent it names' guarantee.",
      "evidence": "selection.ts:126 sets only AGENT_HARNESS; resolver.ts:133-137 uses resolveEnvHarnessPath which prefers env.AGENT_CLI_PATH when no explicit harnessName/cliPath is passed (index.ts:141 calls resolveHarness({ cliPath: [redacted] })).",
      "suggestion": "When pinning a harness, also clear/scope AGENT_CLI_PATH (or pass the harness name explicitly) so the pinned name deterministically selects the binary."
    },
    {
      "priority": "info",
      "confidence": "high",
      "category": "testing",
      "file": "packages/code/tests/workspace-manual-credentials.test.ts",
      "line": "62",
      "issue": "The full suite reports 3 failures; all are pre-existing environmental, not regressions from this change.",
      "evidence": "`bun run test` = 2275 pass / 3 fail: agent-model (env AGENT_MODEL=opencode-go/deepseek-v4.1-flash inherited), workspace-manual-credentials (env DEVINTERN_WORKER_SUBPROCESS=1 causes early null), cli.test.ts (offline network). Re-running with `env -u AGENT_MODEL ...` = 9 pass and `env -u DEVINTERN_WORKER_SUBPROCESS ...` = 3 pass.",
      "suggestion": "No action for this change; consider unsetting these inherited vars in the CI/harness that runs the suite."
    }
  ],
  "approved": true
}

Further artifacts omitted because they exceed the comment preview budget.

@danii1

danii1 commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Visual overview of the per-schedule agent selection added by this PR:

Diagram showing per-automation and per-estimation harness, model, and effort selection; environment precedence; harness pinning and failover behavior; and live reload.

Each automation or estimation can select its own agent. Entry model and effort apply when paired with harness; a pinned harness opts that schedule out of workspace failover. Changing the harness drops inherited model/effort unless explicitly set. Live reload updates future occurrences while active runs keep their original selection.

Examples show selection fields only, not complete schedule definitions. Image generated with OpenAI image generation and checked against the current PR diff.

# Conflicts:
#	packages/code/src/lib/automation/config.ts
@danii1

danii1 commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

danii1 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

@devintern-ai Please resolve this PR's conflicts against its base branch main on the omarchy worker. Merge latest main into the existing branch without rewriting history or force-pushing. Preserve behavior, run relevant tests/checks, push to the same PR branch and report results here. No merge, close, deploy, or changes to PR #224.

danii1 and others added 2 commits November 13, 2026 20:38
# Conflicts:
#	docs/code/workspaces.md
#	packages/code/src/lib/automation/acquirer.ts
#	packages/code/src/lib/workspace/workspace-worker.ts
#	packages/code/tests/automation-acquirer.test.ts
…esolution

- A `model` without `harness` on an automation/estimation is no longer
  silently ignored: it is written to the primary harness's own
  `<HARNESS>_MODEL`, so `model = "sonnet"` works while keeping failover and
  a fallback harness keeps its default model. A pinned `model` also
  outranks an inherited `<HARNESS>_MODEL`. `effort` applies without a pin.
- Add `[workspace].conflict_resolution_harness/_model/_effort`, applied to
  GitHub and GitLab automatic conflict resolution. `runWithFailover` gains a
  `harnessPin` option: a pinned run spawns once on that agent and defers on
  a usage limit instead of failing over. Startup/reload warns when the pin's
  CLI is missing.
- Team-scoped estimations (added on main) apply the entry selection too.
- Fix PR tests for main's async `startWorkerFailover`.
- Move scheduled-job context resolvers to `workspace/schedule-context.ts` to
  keep `workspace-worker.ts` under the max-lines limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@danii1 danii1 changed the title [DEV-184] Per-automation and per-estimation agent harness, model, and effort selection [DEV-184] Per-job agent harness, model, and effort for automations, estimations, and conflict resolution Nov 13, 2026
danii1 and others added 3 commits November 13, 2026 20:52
The selection canonicalizes aliases before spawning, so the child never saw
"gemini" and the resolver's deprecation warning was lost. Emit it at parse
time, naming the entry and key. Adds alias tests (agy, gemini, alias vs
canonical primary).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Model-only examples name the primary harness they assume (claude-code).
- Use gpt-5.2 for the Codex example, matching the rest of the docs.
- Conflict agent applies to GitHub auto/scheduled and GitLab auto only.
- Describe the real deferral behavior for a pinned harness on a usage limit
  (three consecutive deferrals, then wait for head/base to move).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Users write the binary name in AGENT_HARNESS chains (claude,codex,grok) and
in per-job harness settings; it now resolves like agy -> antigravity.
Docs list the alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@danii1
danii1 merged commit 7ac3885 into main Nov 13, 2026
1 check passed
@danii1
danii1 deleted the feature/dev-184 branch November 13, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devintern-authored Pull request written by DevIntern working its own backlog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant