Spike: Project Context Init Flow
Create a new flow for new projects to add context for use by Duo Agent Platform. * Creates a basic AGENTS.md and potential sub AGENTS.md (same as init command of CLIs) in a new MR * Subfolders created for skills, rules, etc. and adds README files | Screenshots | | ------ | | ![image](/uploads/6003d2fd6d74c20c4ee6f4c974ad960c/image.png){width=900 height=125}| |![image](/uploads/737ecbe5d8ac31c4a8d20f5cb222d59d/image.png){width=900 height=132}| |![image](/uploads/9cbb52faee578287dd934b9bf155ba0f/image.png){width=900 height=282}| |![image](/uploads/829fc45785a1e4b385f91285bdae86be/image.png){width=900 height=547}| ## Implementation Plan ### AI Gateway (`ai-assist` repo) Related MR: https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/merge_requests/4851 1. Add `duo_workflow_service/agent_platform/v1/flows/configs/project_context_init/1.0.0.yml` to the flow registry with two components: - `context_analyzer` (`AgentComponent`) — reads the repo tree, detects languages, existing agent context files (AGENTS.md, CLAUDE.md, CURSOR.md, .cursorrules, etc.), and tooling configs. Retrieves the current user ID via `get_current_user` for MR assignment. Toolset: `list_dir`, `find_files`, `read_file`, `get_project`, `get_current_user` - `init_writer` (`AgentComponent`) — generates a minimal, evidence-grounded `AGENTS.md` (no boilerplate; no `skills/`/`rules/` stubs), optional sub-`AGENTS.md` only for subdirs with distinct tooling, then opens a draft MR assigned to the initiating user. Toolset: `create_file_with_contents`, `mkdir`, `create_branch`, `run_git_command`, `create_merge_request` 2. Add prompts for both components under `ai_gateway/prompts/definitions/` 3. Add model selection entries for both components in `ai_gateway/model_selection/unit_primitives.yml` (`unit_primitive: duo_agent_platform`, default model: `claude_sonnet_4_6`) ### GitLab Monolith (`gitlab` repo) All monolith changes are gated behind the `duo_project_context_init` feature flag (type: `beta`, group: `group::ai coding`, default: disabled). The flag must be checked at every entry point: the controller, the service, the sidebar, and the frontend route. #### Feature Flag Definition Create `ee/config/feature_flags/beta/duo_project_context_init.yml`: ```yaml name: duo_project_context_init introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/226355 rollout_issue_url: # add rollout issue URL milestone: '17.11' group: group::ai coding type: beta default_enabled: false ``` Run `bin/feature-flag duo_project_context_init --type beta` to generate this file. #### 1. Backend: `ExecuteWorkflowService` validation enhancement **File**: `ee/app/services/ai/catalog/execute_workflow_service.rb` Modify `validate` to accept `flow_name_reference?` as a bypass for the `json_config` requirement: ```ruby def validate return error('You have insufficient permissions') unless allowed? return error('JSON config is required') unless json_config.present? || foundational_flow? || flow_name_reference? return error('Goal is required') unless goal.present? ServiceResponse.success end def flow_name_reference? @flow_definition.present? && !foundational_flow? end ``` When `json_config` is nil, `StartWorkflowService#serialized_duo_flow_config` already returns nil, so `DUO_WORKFLOW_FLOW_CONFIG` is not set. The AI Gateway executor then resolves the flow YAML from the registry by name automatically via `FlowConfig.from_yaml_config`. #### 2. Backend: `InitProjectContextService` **File**: `ee/app/services/ai/duo_workflows/init_project_context_service.rb` New service that calls `ExecuteWorkflowService` with: - `flow_definition: "project_context_init/v1"` - `container: project` - `goal: "Initialize project context for Duo Agent Platform"` - No `json_config` needed Guard the service with the feature flag: ```ruby def execute return ServiceResponse.error(message: 'Feature not available') unless Feature.enabled?(:duo_project_context_init, project) # ... call ExecuteWorkflowService end ``` #### 3. Backend: Controller **File**: `ee/app/controllers/projects/duo_agents_platform_controller.rb` - Add `'onboarding'` to `DUO_AGENT_PLATFORM_ROUTES` for correct `feature_category` - Add `'onboarding'` to `specific_vueroute?` and `authorized_for_route?` (accessible to any user who can `:duo_workflow` on the project) - Add `set_has_agents_md` before_action scoped to the onboarding route only, gated by the feature flag: ```ruby before_action :set_has_agents_md, only: [:show] def set_has_agents_md return unless params[:vueroute] == 'onboarding' return unless Feature.enabled?(:duo_project_context_init, @project) gon.push(has_agents_md: agents_md_exists?) end ``` Where `agents_md_exists?` checks for `AGENTS.md` in both the project root and `.ai/AGENTS.md`. #### 4. Backend: Rails routes **File**: `ee/config/routes/project.rb` Add a named route helper for the sidebar: ```ruby scope :automate do get '/(*vueroute)' => 'duo_agents_platform#show', as: :automate, format: false get 'onboarding', to: 'duo_agents_platform#show', as: :automate_onboarding, format: false end ``` #### 5. Backend: Sidebar **File**: `ee/lib/sidebars/projects/super_sidebar_menus/duo_agents_menu.rb` Add an "Onboarding" menu item, rendered only when the feature flag is enabled: ```ruby override :configure_menu_items def configure_menu_items add_item(duo_agents_runs_menu_item) add_item(duo_agents_onboarding_menu_item) if Feature.enabled?(:duo_project_context_init, context.project) true end def duo_agents_onboarding_menu_item ::Sidebars::MenuItem.new( title: s_('DuoAgentsPlatform|Onboarding'), link: project_automate_onboarding_path(context.project), active_routes: { controller: :duo_agents_platform }, item_id: :agents_onboarding ) end ``` #### 6. Frontend: Router constants **File**: `ee/app/assets/javascripts/ai/duo_agents_platform/router/constants.js` ```javascript export const AGENTS_PLATFORM_ONBOARDING_ROUTE = 'onboarding_index'; ``` #### 7. Frontend: Router **File**: `ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js` Add a new top-level route tree, conditionally included when `glFeatures.duoProjectContextInit` is enabled: ```javascript ...(glFeatures.duoProjectContextInit ? [{ component: NestedRouteApp, path: '/onboarding', meta: { text: s__('DuoAgentsPlatform|Onboarding') }, children: [ { name: AGENTS_PLATFORM_ONBOARDING_ROUTE, path: '', component: ProjectContextOnboardingPage, }, ], }] : []), ``` This gives the URL `/automate/onboarding` and the breadcrumb "Automate > Onboarding" automatically via the existing router-driven breadcrumb system. #### 8. Frontend: Onboarding page component **File**: `ee/app/assets/javascripts/ai/duo_agents_platform/pages/onboarding/project_context_onboarding_page.vue` A full page component with: - `PageHeading` with title "Set up your project for Duo Agent Platform" - Description explaining what the init flow does (creates `AGENTS.md`, sub-files, skill/rule stubs) - **AGENTS.md absent state**: primary "Initialize project context" `GlButton` that calls `InitProjectContextService`; button is disabled with a spinner while the flow session is in progress - **AGENTS.md present state**: a `GlAlert` (variant: success) informing the user that context has already been initialized, with a link to the resulting MR - Reads `hasAgentsMd` from `window.gon?.has_agents_md` (injected by the controller) to determine which state to render - On success, shows the success state in-page (no full redirect needed) ### What is explicitly NOT needed - No new API endpoint - No AI Catalog registration or `ItemConsumer` - No foundational flow registration (avoids appearing in the group settings UI) - No full YAML bundled in the monolith - No new DB column to track init state (file presence is the guard) - No `skills/` or `rules/` directory stubs (removed from scope)
issue