Conversation
- Add baseUrl and model to AgentConfig; saveAgentConfig accepts 'apiKey'|'baseUrl'|'model' - Add AGENT_BASE_URL_ENV mapping providers to their env var names - BaseAgentAdapter: resolveBaseUrl() injects env var from config when user hasn't set it; resolveModel(taskModel?) applies per-task then falls back to config default - ClaudeAdapter: overrides resolveBaseUrl() to also inject CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 when a baseUrl is active - Codex/GeminiAdapter: buildArgs(prompt, model?) threads --model flag - ProcessSpawner/adapter: spawn() accepts optional model param (interface compliance) - EventDrivenWorkerPool: passes task.model to spawn() - TaskManager: preserves model on retry and resume - Database migration v16: adds model TEXT column to tasks table - TaskRepository: persist/restore model field; Zod schema + row type updated - Domain: model field on Task, TaskRequest, PipelineStepRequest, PipelineCreateRequest, ScheduleCreateRequest, ScheduledPipelineCreateRequest, LoopCreateRequest, OrchestratorCreateRequest; propagated in createTask, createLoop, createOrchestration factories - MCP: DelegateTask/ScheduleTask/CreatePipeline/SchedulePipeline/CreateLoop/ScheduleLoop schemas gain model field; ConfigureAgent gains baseUrl+model set/check; ListAgents exposes baseUrl/model; handleDelegateTask wires model to TaskRequest; all handlers thread model through - CLI: beat run --model/-m flag; agents config set accepts baseUrl/model keys; agents config show displays baseUrl and model; shell history warning only for apiKey - MCP instructions: document model resolution order and ConfigureAgent baseUrl/model usage
- Add missing `model` field to CreateOrchestrator MCP tool (Zod schema, inputSchema, and handler) so orchestrations can use per-task model overrides - Thread shared `model` into taskTemplate for scheduled pipelines so the default model propagates to triggered pipeline tasks - Add --model/-m flag to `beat orchestrate` CLI command - Include model in OrchestratorStatus MCP response and CLI status output
… docs (task-2026-04-01_shepherd-fixes) - Thread orchestration model to inner loop createLoop() call so iterations respect the --model flag passed to CreateOrchestrator - Add Claude-specific warning in ConfigureAgent (set/check) and ListAgents when baseUrl is configured without an API key (login-based auth ignores baseUrl) - Document in ConfigureAgent tool description that clearing individual fields requires action=reset or the CLI (MCP set action requires non-empty values) - Tests: verify model is propagated to loop taskTemplate; verify Claude warning appears in set/check actions and ListAgents; verify no warning for other agents
Greptile SummaryThis PR threads Key changes:
Confidence Score: 5/5Safe to merge — all remaining findings are P2 style/cleanup items with no correctness or data-integrity impact. The feature is fully implemented end-to-end with correct precedence logic, env-var safety, backward-compatible migration, and comprehensive tests (1,546 passing). The two findings are both P2: one is a latent trap in a class confirmed unused in the production path, and the other is unreachable dead code in a message-building branch. Neither affects current behaviour. src/implementations/process-spawner.ts (model silently discarded), src/adapters/mcp-adapter.ts (dead message branches) Important Files Changed
Sequence DiagramsequenceDiagram
participant CLI as beat run / MCP tool
participant TM as TaskManager
participant Repo as TaskRepository (DB)
participant WP as EventDrivenWorkerPool
participant Reg as AgentRegistry
participant Adapter as ClaudeAdapter / CodexAdapter / GeminiAdapter
participant Proc as Child Process
CLI->>TM: delegate(TaskRequest { model? })
TM->>Repo: save(Task { model? })
Note over Repo: migration v16 — model TEXT column
TM->>WP: enqueue(task)
WP->>Reg: getAdapter(task.agent)
Reg-->>WP: AgentAdapter
WP->>Adapter: spawn(prompt, cwd, taskId, task.model)
Note over Adapter: resolveModel(taskModel)<br/>1. per-task model<br/>2. agentConfig.model<br/>3. CLI default (none)
Note over Adapter: resolveBaseUrl()<br/>1. user env var (skip inject)<br/>2. agentConfig.baseUrl
Adapter->>Adapter: buildArgs(prompt, resolvedModel)<br/>e.g. [--model, claude-opus-4-5, --, prompt]
Adapter->>Proc: spawn(cmd, args, { env: {ANTHROPIC_BASE_URL?, ...} })
|
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| spawn(prompt: string, workingDirectory: string, taskId?: string, _model?: string): Result<{ process: ChildProcess; pid: number }> { |
There was a problem hiding this comment.
_model silently dropped in ClaudeProcessSpawner
ClaudeProcessSpawner accepts the model parameter but discards it entirely. This is confirmed safe today — bootstrap.ts registers this class as the processSpawner service but that service is never retrieved by any production consumer (the agentRegistry uses ClaudeAdapter directly). However, the silent discard creates a trap: if ClaudeProcessSpawner is ever re-wired into a live spawn path, tasks that specify a model will silently use the CLI's default model instead of the requested one, with no error or warning.
Consider either:
- Adding a
TODO/FIXMEcomment that explicitly documents the model is intentionally not forwarded, or - Implementing it the same way
ClaudeAdapter.buildArgsdoes (['--model', model]) so the class is a complete implementation of the updated interface.
Replace misleading "placeholder" wording with explanation of why taskTemplate exists alongside loopConfig on scheduled loops.
Code Review FindingsI've analyzed the code review reports and identified blocking issues requiring attention before merge: CRITICAL (5 issues - 95% confidence)
HIGH (6 issues - 80-92% confidence)
Posting inline comments on specific files now. |
BLOCKING ISSUES (80%+ confidence)CRITICAL (95% confidence)1. Model field stripped on DB roundtrip (4 locations)Files affected:
The
Fix: Add // TaskRequestSchema
agent: z.enum(AGENT_PROVIDERS_TUPLE).optional(),
model: z.string().optional(),
// PipelineStepsSchema (within step object)
agent: z.enum(AGENT_PROVIDERS_TUPLE).optional(),
model: z.string().optional(),
// LoopConfigSchema
agent: z.enum(AGENT_PROVIDERS_TUPLE).optional(),
model: z.string().optional(),2. Orchestration model not persisted to databaseFiles affected:
The
Result: Fixes required:
HIGH (80-92% confidence)3. loadAgentConfig() called 3x per spawnFile: Each spawn() invocation calls loadAgentConfig() three times:
Each call reads ~/.autobeat/config.json from disk and parses JSON. Under concurrent task delegation (multiple workers spawning in parallel), this triples disk I/O. Fix: Load config once at the start of spawn() and pass it to all three resolution methods. 4. JSON Schema model field validation inconsistentFiles: The
MCP clients rely on JSON Schema for validation. Inconsistent constraints cause confusion and may allow invalid values to be sent. Fix: Add 5. ConfigureAgent set action — partial-write riskFile: The Fixes (choose one):
6. CLI baseUrl validation missingFile: The CLI Fix: Validate with Recommendation: These issues must be addressed before merge. The CRITICAL issues (5 instances) cause silent data loss where the feature appears to work initially but fails after persistence. The HIGH issues prevent the feature from working correctly in production workloads. |
MEDIUM-CONFIDENCE SUGGESTIONS (60-79%)These don't block merge but should be tracked for next release: Complexity
Performance
Architecture
Testing
SUMMARYBlocking Issues: 6 (including 2 CRITICAL with 95% confidence, 4 HIGH with 80-92%) The PR demonstrates strong architectural consistency for the model passthrough feature across all layers. However, the 5 CRITICAL data-loss issues in persistence schemas and the HIGH-severity validation gaps must be fixed before merge. These are not architectural concerns but implementation gaps where the feature was added to domain types and APIs but not fully integrated into the persistence and validation layers. Once fixed, this will be a clean, well-tested feature addition. |
The CLI path for 'beat agents config set <agent> baseUrl <value>' accepted any string without validation, while the MCP ConfigureAgent tool correctly enforced z.string().url(). Adds new URL() validation before saveAgentConfig to reject malformed URLs with a user-friendly error message, matching the MCP validation boundary. Empty string (clear) is still allowed.
BaseAgentAdapter.spawn() previously called loadAgentConfig() independently inside resolveAuth(), resolveBaseUrl(), and resolveModel(), causing three separate readFileSync + JSON.parse operations per spawn. Config is now loaded once at the top of spawn() and passed as an AgentConfig parameter to each of the three methods. ClaudeAdapter.resolveBaseUrl() updated to accept and forward the pre-loaded config to super.
…hedules, and orchestrations Add model to TaskRequestSchema in loop-repository and schedule-repository so Zod does not strip it on read-back. Add model to PipelineStepsSchema step object and LoopConfigSchema in schedule-repository for the same reason. Add migration v17 to add model column to the orchestrations table, and wire model through OrchestrationRowSchema, OrchestrationRow, toRow(), rowToOrchestration(), and the INSERT/UPDATE SQL statements.
…onstraints - configure-agent-partial-write: replace sequential early-return saves with collect-all pattern; errors now report which fields were already saved via alreadySaved[] to make partial-write visible instead of silent - json-schema-model-validation-inconsistent: add minLength:1/maxLength:200 to model fields in ScheduleTask, CreatePipeline (step+top-level), SchedulePipeline (step+top-level), CreateLoop, ScheduleLoop, CreateOrchestrator, and ConfigureAgent inputSchema blocks — matching the existing Zod schemas and the DelegateTask JSON Schema pattern - record-string-unknown-type-safety: replace Record<string,unknown> with typed CheckPayload and SetPayload interfaces in handleConfigureAgent - duplicated-claude-baseurl-warning: extract getClaudeBaseUrlWarning() private helper; remove three copies of identical condition+string
…ths (batch-e) - Add retry() model threading tests: verify model survives retry for both set and undefined values, preventing silent regression if the field is dropped - Add resume() model threading tests: same coverage for resume path - Add schedule manager model threading tests: createSchedule threads model to taskTemplate; createPipeline threads shared and per-step model; createScheduledLoop threads model through both taskTemplate and loopConfig - Fix stale docstring in ClaudeAdapter: remove reference to prompt transformation that was dropped during the v0.5.0 BaseAgentAdapter refactor
Release v1.2.0 with two features merged since v1.1.0: - Terminal Dashboard (#131): Ink-based TUI (`beat dashboard`/`dash`) with 4 panels, keyboard nav, detail views, per-panel filters - Agent baseUrl & model passthrough (#130): per-agent config, --model CLI flag, provider env var injection, Migration 16 No breaking changes. Fully additive. Also includes biome formatter auto-fixes for src/adapters/mcp-adapter.ts, src/cli/dashboard/*, src/implementations/base-agent-adapter.ts, and related tests — these landed on main via admin-merged PRs and were blocking CI.
Two pre-existing test bugs that only surfaced once CI got past the formatter step on this release PR: 1. panel.test.tsx:50 — 'renders children' was wrapping a raw string in <React.Fragment> inside a <Box>. Ink requires text to be wrapped in <Text>. On macOS local the render was lenient; on Linux CI the frame came back as '\n'. Fixed by using <Text>child content</Text>. 2. use-keyboard.test.tsx press() — the 0ms setTimeout flush wasn't giving ink's useInput effect enough time to re-register after React 19 state commits on Linux CI runners. Escape (\x1B) also needs ink's internal escape-sequence debounce to settle. Bumped the macrotask flush to 10ms and added explicit microtask flushes on both sides. Local test duration for this suite goes from ~100ms to ~450ms — acceptable for reliability. These two tests have never run green in CI (both #130 and #131 were admin-merged past a failing biome step, so the test phase was skipped). Not regressions — latent bugs surfaced by fixing the formatter block.
## Summary Release v1.2.0 — **Terminal Dashboard & Agent Config Passthrough**. Fully additive, no breaking changes. ### Features Since v1.1.0 - **Terminal Dashboard** (#131): `beat dashboard` / `beat dash` Ink TUI with 4 panels (loops, tasks, schedules, orchestrations), keyboard navigation (Tab/Shift+Tab, 1-4, j/k, Enter, Esc, f, q, r), detail views per entity, per-panel filter cycles, truncation indicators, and smart EmptyState. - **Agent baseUrl & model passthrough** (#130): Per-agent `baseUrl` and `model` in `~/.autobeat/config.json`; `--model`/`-m` CLI flag on `beat run` and `beat orchestrate`; provider env var injection (`ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`, `GEMINI_BASE_URL`); Claude experimental-betas auto-disable on custom `baseUrl`; extended `ConfigureAgent`/`ListAgents` MCP tools. ### Database - **Migration 16**: Adds `model` column to both `tasks` and `orchestrations` tables. Auto-applies on startup, backward compatible. ## Files Changed - `package.json` / `package-lock.json` — version bump 1.1.0 → 1.2.0 - `CHANGELOG.md` — v1.2.0 entry under `[Unreleased]` - `docs/releases/RELEASE_NOTES_v1.2.0.md` — new, required by release workflow - `docs/releases/RELEASE_NOTES.md` — index updated (v1.2.0 latest, v1.1.0 moved) - `docs/FEATURES.md` — added v1.2.0 section, reframed stale "Web UI" line as "No web-based UI (TUI dashboard available via `beat dashboard`)" - `docs/ROADMAP.md` — current status → v1.2.0, added to Released Versions and Version Timeline, removed TUI dashboard from upcoming Monitoring & REST API section - `CLAUDE.md` — replaced Release Process section with a mechanical recipe (version decision matrix, file checklist, validation commands, Snyk step, commit/PR/merge flow, workflow trigger, post-release verification, gotchas including orphan-publish recovery) ### Formatter Cleanup (bundled) This PR also includes biome formatter auto-fixes for files landed on main via admin-merged PRs #130/#131 that were blocking CI. Files affected: `src/adapters/mcp-adapter.ts`, `src/cli/dashboard/{components,types,use-keyboard,views}`, `src/implementations/base-agent-adapter.ts`, and related tests. Produced by `npm run check:fix` (formatter-only, no semantic changes). ## Security Scan Ran `mcp__Snyk__snyk_code_scan` on `src/` with `severity_threshold=medium`. Found **2 pre-existing Medium Path Traversal findings** in `src/core/orchestrator-state.ts` / `src/cli/commands/orchestrate.ts` / `src/utils/validation.ts` (unchanged files from v1.0.0 orchestration code). **Not introduced by this release.** No new findings from #130 or #131 changes. Not blocking. ## Test plan - [x] `npm run typecheck` clean - [x] `npm run check` clean (after formatter fixes) - [x] `npm run build` clean - [x] Grouped test suites pass locally: core (359), handlers (168), services (179), repositories (211), adapters (110), implementations (327), cli (295), dashboard (253), scheduling (139), checkpoints (36), error-scenarios (31), orchestration (79), integration (70/75 — known flaky `worker-pool-management.test.ts` OOMs in Claude Code only, passes in CI) - [ ] CI runs full `test:all` — source of truth - [ ] Squash merge → trigger release workflow manually via `gh workflow run release.yml --ref main` --------- Co-authored-by: Dean Sharon <deanshrn@gmain.com>
Summary
baseUrlandmodelfields to per-agent configuration (~/.autobeat/config.json), enabling custom API endpoints and model selection for Claude Code, Codex CLI, and Gemini CLImodelthrough the entire task lifecycle: domain types → MCP tools → CLI → spawn pipeline → database persistence (migration v16)baseUrlas the provider-specific env var (ANTHROPIC_BASE_URL,OPENAI_BASE_URL,GEMINI_BASE_URL) at spawn time with user env var precedencebaseUrlis configured (prevents proxy failures)--model/-mflag tobeat runandbeat orchestrateCLI commandsConfigureAgentandListAgentsMCP tools withbaseUrl/modelsupport, including Claude-specific warning when baseUrl is set without an API keyTest plan
npm run build)--modelflag in args, config model fallback, per-task model override, Claude experimental betas auto-disable--modelflag parsing onbeat runandbeat orchestratebeat agents config set claude baseUrl https://proxy.example.com→ verify shown inbeat agents config show claudebeat run --model claude-sonnet-4-6 "hello"→ verify--modelin spawned args