Skip the clone for foundational agents that need no checkout
What does this MR do and why?
Foundational agents can now say they need no repository checkout, the way foundational flows
already can. Data Analyst, Permissions Assistant and Flow Creator do, so when one of them runs
in a CI job (started over MCP with start_duo_session) the job no longer clones the project
first. Orbit and CI Expert keep the clone, because they use file and command tools.
This is the first step of #631699: an agent has to resolve to none before the Workhorse
runtime will take it, and before a Workhorse session can resume on Workhorse rather than CI.
why agents resolved to full, and how each agent was classified
Ai::Catalog::CodingEnvironment.resolve looked in a catalog flow_config and then in the
FoundationalFlow registry. Chat agents are in neither, so every agent fell through to the
default :full. Two things follow from that:
StartWorkflowServiceclones the repository and runs the checkout commands for every agent session in CI (git_clone_variables,coding_environment_commands). On GitLab.com that was 7–13 minutes ofgitlab-org/gitlabper turn in the walkthrough.ExecuteRunServicerefuses:fullon Workhorse (SUPPORTED_CODING_ENVIRONMENTS), andWorkflow#last_runtimederives:cifor a session without a workload, so a Workhorse agent session would resume on CI.
Ai::FoundationalChatAgent gains a coding_environment attribute, and the resolver consults
it after the flow registry. The lookup is exact on the workflow definition, like
Workflow#chat?, so a version that does not exist still gets the default. An undeclared agent
keeps :full, which keeps the resolver's rule that a missing declaration can only widen the
environment.
Which agents can declare none was decided from the AI Gateway flow configs (origin/main
at 728d081c17), not from the tools: list in FoundationalChatAgentsDefinitions, which
is only displayed in the AI Catalog. The DWS chat workflow binds the YAML toolset, filtered by
the session's privileges, and MCP-started sessions get DEFAULT_PRIVILEGES, which include
file and command access.
| Agent | Flow config | Tools that need the clone | Declares |
|---|---|---|---|
| Data Analyst | ai/features/insights/analytics_agent/config/2.0.0.yml |
none: GLQL, notes, Orbit MCP | none |
| Permissions Assistant | .../configs/duo_permissions_assistant/2.0.0.yml |
none: gitlab_graphql, set_form_permissions |
none |
| Flow Creator | .../configs/flow_creator/1.0.0.yml |
none: gitlab_documentation_search |
none |
| Orbit | .../configs/orbit_agent/1.0.0.yml |
9 of 28: read_file, read_files, list_dir, find_files, grep, create_file_with_contents, edit_file, mkdir, run_command |
default |
| CI Expert | none in AIGW; fetched from the AI Catalog at image build | its prompt has a section for a checked-out repository | default |
| Planner | none in AIGW; AI Catalog (1.19.0 on GitLab.com) | none today, but the catalog item can change without a GitLab release | default |
| Support Assistant | none in AIGW; AI Catalog (1.7.0) | none today, same reason as Planner | default |
| Security Analyst | none in AIGW; AI Catalog (1.24.0) | 7 of 35, including read_file, edit_file, grep, run_command |
default |
| Onboarding guide | none in AIGW; AI Catalog (2.2.0) | read_file, list_dir, find_files |
default |
A file or command tool reaches the job's CLI through Workhorse's /ws path and works on the
clone; GitLab API, GraphQL and known MCP tools are answered by Workhorse itself or by the AI
Gateway. With GIT_STRATEGY: none the job still starts: recommend_reviewers/v1 already runs
that way, and duo-cli takes the project from GITLAB_PROJECT_PATH and
DUO_WORKFLOW_PROJECT_ID when there is no repository.
Only an agent with a flow_version can declare none. The others get their tools from the AI
Catalog, which can change without a GitLab release, so Planner and Support Assistant keep the
default even though their tools need no clone today. A file or command tool added to one of the
three agents later has to come in a new major flow config version, with flow_version moved and
none dropped in the same GitLab merge request: older instances would otherwise pick it up
through ^2.0.0. The developer docs now say so.
References
Part of #631699. Related: !257062 (merged) (agents over MCP on CI), #628435 (closed) (ExecuteRunService).
Screenshots or screen recordings
No UI change. The CI job of a Data Analyst session started over MCP:
| Before | After |
|---|---|
| clones the project, then runs the checkout commands | GIT_STRATEGY: none, no checkout commands |
How to set up and validate locally
steps and what I got in GDK
GDK serves the main checkout, which is a few days behind master, and its databases do not
have master's newest migrations. So I ran these commits on top of that checkout instead: I
cherry-picked them onto 0a80f055 together with af87792a (default_runtime_for) and
served that from a second Puma on port 3999. The changed lines are identical to this branch.
The CI job ran on the GDK runner, and DWS and the AI Gateway are GDK's own.
-
Check what each agent resolves to:
%w[analytics_agent/v1 duo_permissions_assistant/v1 flow_creator/v1 orbit_agent/v1 ci_expert_agent/v1 chat developer/v1].each do |definition| env = Ai::Catalog::CodingEnvironment.resolve(workflow_definition: definition) runtime = Ai::Catalog::CodingEnvironment.default_runtime_for(definition) puts format('%-30s %-5s %s', definition, env, runtime) endWhat I got:
analytics_agent/v1 none workhorse duo_permissions_assistant/v1 none workhorse flow_creator/v1 none workhorse orbit_agent/v1 full ci ci_expert_agent/v1 full ci chat full ci developer/v1 full ci -
Start a Data Analyst session over MCP with an OAuth token that has the
mcpscope:curl -s -X POST "http://gdk.test:3000/api/v4/mcp" -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"start_duo_session","arguments":{"project_id":"gitlab-org/gitlab-test","agent":"analytics_agent/v1","goal":"How many merge requests were merged in this project in the last 30 days?"}}}'What I got:
Session 1028 started. It runs in a CI job, which can take a few minutes to start., with workload 548. -
Look at the job the workload created:
build = Ci::Workloads::Workload.find(548).pipeline.builds.first build.yaml_variables.to_h { |v| [v[:key].to_s, v[:value]] }.slice('GIT_STRATEGY', 'GIT_DEPTH', 'GIT_FETCH_EXTRA_FLAGS') Array(build.options[:script]).join("\n").include?('git checkout -B')What I got:
{"GIT_STRATEGY"=>"none"}andfalse. The job succeeded in 31.9 s, andget_duo_sessionreturned the agent's answer with statusinput_required: "No merge requests were merged in the last 30 days in the Gitlab Test project ...", backed by a GLQL query. -
For contrast, an Orbit session (workload 549) still clones:
{"GIT_DEPTH"=>"0", "GIT_FETCH_EXTRA_FLAGS"=>"--prune --quiet --filter=blob:none"}, and its script runs the checkout commands. -
Specs:
bin/rspec ee/spec/models/ai/catalog/coding_environment_spec.rb ee/spec/models/ai/foundational_chat_agent_spec.rb bin/rspec ee/spec/services/ai/duo_workflows/start_workflow_service_spec.rb -e 'coding_environment declaration'Of the 14 chat agent examples (
-e 'foundational chat agent'oncoding_environment_spec.rband the service spec), 6 fail withcoding_environment.rbfrommaster. All pass here.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.