Skip to content

feat(config): persist per-project agent config and resolve it at spawn #107

@neversettle17-101

Description

@neversettle17-101

Summary

Each project should be able to carry its own agent configuration (model, flags, permission mode, agent-specific keys), but today there is no durable per-project agent config. The legacy TS version resolved this from agent-orchestrator.yaml ("global vs project config resolution"); the Go rewrite split global settings into env vars and project identity into the projects table, but the per-project agent config half was never wired to storage.

The type-level scaffolding already exists — it just has no data source.

Current state

Wired today (per-session, at spawn):

  • ports.SpawnConfig carries Harness, Prompt, AgentRules (backend/internal/ports/session.go:7).
  • Empty Harness falls back to the daemon-global AO_AGENT default (backend/internal/daemon/lifecycle_wiring.go:142).

Designed but NOT wired:

  • ports.AgentConfig (map[string]any) — "values loaded from the selected agent's config section" (backend/internal/ports/agent.go:54).
  • ports.ConfigSpec / ConfigField — typed, adapter-declared config keys (backend/internal/ports/agent.go:57).
  • LaunchConfig.Config — the carrier into the launch command (backend/internal/ports/agent.go:85).

The gaps:

  • projects table has no agent-config columns — only id, path, repo_origin_url, display_name, registered_at, archived_at (backend/internal/storage/sqlite/migrations/0001_init.sql:8).
  • At spawn, LaunchConfig is built with Config left empty (backend/internal/session_manager/manager.go:139).
  • claudecode.GetConfigSpec returns an empty spec ("no agent-specific config keys yet", backend/internal/adapters/agent/claudecode/claudecode.go:85).

Proposed slice

Following the rewrite's patterns (env for global, DB rows for per-project, validation owned by adapters):

  1. Storage — persist per-project agent config keyed by project_id (e.g. a projects.agent_config JSON column, or a project_agent_config table keyed by project_id + harness). Add sqlc queries + migration.
  2. Resolution — in startSession / session_manager, load the project's config and populate LaunchConfig.Config before GetLaunchCommand.
  3. Validation — each adapter validates its own keys against its ConfigSpec ("Agent adapters own validation for their custom keys").
  4. CLI/API surface — set/get per-project agent config (e.g. extend ao project + a projects controller route).

Out of scope

  • Pinning a default harness per project (separate concern; can be a follow-up using the same storage).
  • Notifier/tracker/SCM per-project config (this issue is scoped to agent config).

Acceptance criteria

  • A project can store agent config that survives daemon restart.
  • A spawn for that project receives the resolved AgentConfig in LaunchConfig.Config.
  • Invalid keys/values are rejected by the owning adapter with a clear error.
  • Works OS-agnostically (macOS/Linux/Windows); no new env-only config for per-project state.

🤖 Generated with Claude Code

Metadata

Metadata

Labels

adapterAdapter implementation change onlycoding-agentsRuntime + Workspace + Agent adapters laneenhancementNew feature or requeststoragePersistence lane

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions