Skip to content

feat(run): autodiscover project agent config#3681

Merged
Sayt-0 merged 3 commits into
docker:mainfrom
HajimohammadiNet:codex/project-config-autodiscovery
Jul 16, 2026
Merged

feat(run): autodiscover project agent config#3681
Sayt-0 merged 3 commits into
docker:mainfrom
HajimohammadiNet:codex/project-config-autodiscovery

Conversation

@HajimohammadiNet

@HajimohammadiNet HajimohammadiNet commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Refs #2435

Summary

  • autodiscover docker-agent.yaml / docker-agent.yml / docker-agent.hcl for no-argument local docker agent run
  • normalize discovered project configs before sandbox selection so runtime.sandbox: true is honored the same as explicit config paths
  • keep explicit config arguments and --remote runs unchanged
  • update user-facing docs for the new project-file-before-built-in-default behavior

Why

Repositories can now check in a conventional project-level agent config and let developers run docker agent run without remembering a file path. This keeps the first slice focused on autodiscovery and leaves native docker agent new scaffolding for a follow-up.

Testing

  • gofmt
  • git diff --check
  • go test -p=1 ./cmd/root -run TestDiscoverRunAgentArgs -count=1 in golang:1.26.5
  • go test -p=1 ./cmd/root -count=1 in golang:1.26.5
  • ./scripts/build.sh in golang:1.26.5
  • go mod tidy --diff in golang:1.26.5
  • go run ./lint . in golang:1.26.5
  • golangci-lint run --concurrency=2 with v2.12.2 in golang:1.26.5

@HajimohammadiNet
HajimohammadiNet requested a review from a team as a code owner July 16, 2026 12:45
@rumpl

rumpl commented Jul 16, 2026

Copy link
Copy Markdown
Member

and .hcl please

@aheritier aheritier added area/cli CLI commands, flags, output formatting area/docs Documentation changes kind/feat PR adds a new feature (maps to feat:). Use on PRs only. labels Jul 16, 2026

@Sayt-0 Sayt-0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Autodiscovery matches #2435 (including the .hcl request), keeps explicit arguments and --remote untouched, and ships focused tests plus doc updates. One inconsistency blocks approval: discovery runs after the sandbox decision in runRunCommand, so a discovered config declaring runtime.sandbox: true silently runs unsandboxed. Details in the inline comments.

# Severity Finding
1 blocking runtime.sandbox: true in a discovered config is ignored; fix by normalizing args early, like --agent-picker does
2 should Discovery is silent; print which project config was picked
3 nit Stat-error branch needs a comment (and ideally a test)
4 nit Three doc/help mentions still describe the old behavior
5 discussion Trust boundary: a repo-provided config runs MCP command toolsets and session_start hooks with no consent gate; a direnv-style consent prompt could be a follow-up

Verified on PR head: go test -run TestResolveRunAgentFileName ./cmd/root pass, gofmt clean, no conflicts with main.

Comment thread cmd/root/run.go
return nil
}

func (f *runExecFlags) resolveRunAgentFileName(args []string) string {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Discovery at this layer runs after runRunCommand has already made the sandbox decision from args[0]:

  • resolveSandboxDefault(ctx, agentRef, ...) receives agentRef == "" on a no-arg run, so runtime.sandbox: true in a discovered docker-agent.yaml is silently ignored. The same file passed explicitly runs sandboxed.
  • On a --sandbox no-arg run, runInSandbox receives an empty agentRef: the kit build is skipped and sandbox.EnvForAgent forwards nothing. The inner run only works because it re-discovers the file inside the workspace, in a degraded mode compared to an explicit path.

The --agent-picker block already solves this shape of problem by normalizing args before dispatch. Discovery can reuse that pattern in runRunCommand, right after the picker block and before resolveSandboxDefault:

if len(args) == 0 && f.remoteAddress == "" {
	if name, ok := discoverProjectDefaultAgentFile(); ok {
		args = prependAgentRef(name, args)
	}
}

resolveRunAgentFileName then reduces to the previous args[0] read, and explicit, discovered, sandboxed, and remote runs all agree on which config is in play.

Comment thread cmd/root/run.go
if len(args) > 0 {
agentFileName = args[0]
}
agentFileName := f.resolveRunAgentFileName(args)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Discovery is silent: nothing in the output distinguishes a run that picked ./docker-agent.yaml from one using the built-in default agent. Recording mode and worktrees both announce themselves via out.Println; a similar one-liner here keeps surprises down, and matters most for --exec where no TUI sidebar hints at the loaded agent:

out.Println("Using project config: " + agentFileName)

Printed only when the name came from discovery, not from an explicit argument.

Comment thread cmd/root/run.go
if err == nil && !info.IsDir() {
return name, true
}
if err != nil && !errors.Is(err, os.ErrNotExist) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This branch reports a candidate as discovered even though os.Stat failed (e.g. permission error), so the downstream load surfaces a real error instead of silently running the built-in default next to an unreadable docker-agent.yaml. Failing loudly seems right, but two things are missing:

  • a comment: without one the code reads like a bug, and the branch also means an unreadable docker-agent.yaml shadows a readable docker-agent.yml later in the list, which is a deliberate choice worth stating
  • optionally a test locking the behavior; a self-referential symlink named docker-agent.yaml triggers a non-ErrNotExist stat error portably on unix (skip on Windows)

> **No config needed**
>
> Running `docker agent run` without a config file uses a built-in default agent. Perfect for quick experimentation.
> Running `docker agent run` without a config argument uses `docker-agent.yaml`, `docker-agent.yml`, or `docker-agent.hcl` from the current directory when present. Otherwise, it uses a built-in default agent that is perfect for quick experimentation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Three more spots still describe the pre-discovery behavior and now contradict this paragraph:

Location Current text
docs/features/cli/index.md:630 Agent References table, row "Default": "(no argument) uses built-in default agent"
docs/index.md:277 "Zero Config" section: "# Run the built-in default agent"
cmd/root/run.go:124 help example: docker-agent run # built-in default agent

@HajimohammadiNet

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I pushed 636a73f0e to address the actionable items:

  • normalized discovered project configs into args[0] before sandbox resolution, so runtime.sandbox: true is honored the same way as an explicit config path
  • print Using project config: ... only when a project config was autodiscovered
  • documented the non-ErrNotExist stat path and added coverage for the shadowing behavior
  • updated the stale help/docs mentions that still described the old built-in-default-only behavior

For the trust-boundary point around repo-provided configs running command toolsets/hooks, I left that as follow-up scope since it was marked as discussion and would need a broader consent model than this autodiscovery slice.

@Sayt-0

Sayt-0 commented Jul 16, 2026

Copy link
Copy Markdown
Member

looks good now ! thanks for the contribution !

@Sayt-0

Sayt-0 commented Jul 16, 2026

Copy link
Copy Markdown
Member

Can you sign your commits ?

@HajimohammadiNet
HajimohammadiNet force-pushed the codex/project-config-autodiscovery branch from 636a73f to fb65180 Compare July 16, 2026 16:04
@HajimohammadiNet

Copy link
Copy Markdown
Contributor Author

Done, thanks for the reminder. I rewrote the PR commits with SSH signatures and added the signing key to GitHub; the commits now show valid signatures.

@Sayt-0
Sayt-0 merged commit d689125 into docker:main Jul 16, 2026
13 checks passed
@HajimohammadiNet
HajimohammadiNet deleted the codex/project-config-autodiscovery branch July 16, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cli CLI commands, flags, output formatting area/docs Documentation changes kind/feat PR adds a new feature (maps to feat:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants