feat(workflow): add per-repository workflow override support#120
feat(workflow): add per-repository workflow override support#120
Conversation
Implement a two-layer workflow resolution system where a service-level WORKFLOW.md defines global defaults and individual repositories can provide their own WORKFLOW.md to override agent behaviour on a per-repo basis. Key changes: - types.ts: add RepoOverridesConfig interface - workflow.ts: add loadRepoWorkflow() and mergeWorkflows() functions - workflow.test.ts: 13 new tests for merge logic and repo workflow loading - config.ts: add parseRepoOverridesSetting() to read repo_overrides config - config.test.ts: 7 new tests for repo overrides config parsing - orchestrator.ts: add resolveEffectiveWorkflow() and resolveEffectiveConfig(); update executeAgentRun() and runAgentTurns() to use per-issue effective workflow - ARCHITECTURE.md: document two-layer workflow resolution in Configuration section - README.md / README.ko.md / README.ja.md / README.zh-CN.md: add repo_overrides schema, override rules, security boundary, and "Per-Repository Workflow Override" section across all four translations Override rules: - agent_prompt, tools, and max_turns are overridable per repository - Service-level sections (tracker, hooks, workspace) are never overridable - Feature is opt-in via repo_overrides: true in the service WORKFLOW.md
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the flexibility of the workflow configuration by introducing per-repository overrides. It allows project teams to customize agent behavior and prompts for their specific repositories without altering the global service configuration, while strictly enforcing security boundaries for sensitive settings. This change empowers individual teams with more control over their automated processes, making the system more adaptable to diverse project needs. Highlights
Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request introduces a well-designed feature for per-repository workflow overrides, complete with thorough documentation updates across multiple languages and a solid set of new tests. The implementation correctly establishes security boundaries by preventing overrides of service-level configurations. My review found one significant issue where the configuration merging logic performs a shallow merge instead of the documented deep merge, which could lead to unexpected configuration behavior.
There was a problem hiding this comment.
10 issues found across 11 files
Confidence score: 2/5
- There is a concrete security-boundary risk in
apps/work-please/src/orchestrator.tsandapps/work-please/src/workflow.ts: repo-localWORKFLOW.mdcan overridehooks.before_run/hooks.after_run, enabling repository-controlled shell execution that should remain service-controlled. apps/work-please/src/orchestrator.tsalso appears to pass fully merged repo config into runtime loading, making repoclaude/envkeys effective beyond documented overrides and increasing unintended behavior/regression risk.apps/work-please/src/config.tsandapps/work-please/src/config.test.tssuggest policy/implementation drift (prompt_templateallowlist behavior and tests blessing hook overrides), while README/architecture docs currently reinforce the unsafe model instead of the intended boundary.- Pay close attention to
apps/work-please/src/orchestrator.ts,apps/work-please/src/workflow.ts,apps/work-please/src/config.ts,apps/work-please/src/config.test.ts,README.md,README.zh-CN.md,README.ko.md,README.ja.md,ARCHITECTURE.md- enforce non-overridable hooks and align allowlist/docs with actual merge behavior.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:586">
P2: Clarify that `allow` only limits config-section overrides; repo prompt templates still replace the global prompt when present.</violation>
</file>
<file name="ARCHITECTURE.md">
<violation number="1" location="ARCHITECTURE.md:202">
P2: This sentence contradicts the security boundary by listing `hooks.before_run` and `hooks.after_run` as repo-overridable.</violation>
</file>
<file name="README.zh-CN.md">
<violation number="1" location="README.zh-CN.md:551">
P2: The override rules here incorrectly mark `hooks` as repo-overridable, but this feature's security boundary says `hooks` must remain service-controlled. Update the table and `repo_overrides.allow` example so they do not advertise hook overrides.</violation>
</file>
<file name="apps/work-please/src/workflow.ts">
<violation number="1" location="apps/work-please/src/workflow.ts:141">
P1: Repository overrides can currently replace `hooks.before_run` and `hooks.after_run`, which breaks the stated security boundary that hooks must never be overridable.</violation>
</file>
<file name="apps/work-please/src/orchestrator.ts">
<violation number="1" location="apps/work-please/src/orchestrator.ts:265">
P1: Passing the full repo-merged config into the agent runner/env loader makes every `claude`/`env` key in a repo `WORKFLOW.md` effective, not just the documented prompt/tools/max_turns overrides.</violation>
<violation number="2" location="apps/work-please/src/orchestrator.ts:698">
P0: Preserve `hooks` from the global config here; otherwise a repo-local `WORKFLOW.md` can replace `before_run`/`after_run` and execute repository-controlled shell scripts.</violation>
</file>
<file name="apps/work-please/src/config.test.ts">
<violation number="1" location="apps/work-please/src/config.test.ts:810">
P1: Remove `hooks` from the expected default repo override sections; this test currently blesses a repo-level hook override path that contradicts the stated security boundary.</violation>
</file>
<file name="README.ja.md">
<violation number="1" location="README.ja.md:534">
P2: この説明は`WORKFLOW.md`をサービスのグローバル設定ファイルとして扱っており、既存のリポジトリガイダンスと矛盾しています。
(Based on your team's feedback about describing WORKFLOW.md as a target-repo runtime file rather than the primary workspace config.) [FEEDBACK_USED]</violation>
</file>
<file name="apps/work-please/src/config.ts">
<violation number="1" location="apps/work-please/src/config.ts:468">
P2: `prompt_template` is accepted in the allow list, but the merge logic always applies repo prompt overrides regardless of `allowed_sections`, so operators cannot actually disallow prompt-template overrides.</violation>
</file>
<file name="README.ko.md">
<violation number="1" location="README.ko.md:563">
P2: This allowlist example is misleading because repo prompt templates still override the global prompt even when `prompt_template` is omitted. Please include `prompt_template` here or clarify that the allowlist only applies to config sections.</violation>
</file>
Architecture diagram
sequenceDiagram
participant ORCH as Orchestrator
participant WS as Workspace
participant WF as Workflow Service
participant AR as Agent Runner
Note over ORCH,WF: Start Agent Run for Issue
ORCH->>WS: createWorkspace(globalConfig, issue)
WS-->>ORCH: workspacePath
Note over ORCH,WF: NEW: Per-Repository Workflow Resolution
alt repo_overrides is enabled
ORCH->>WF: NEW: loadRepoWorkflow(workspacePath)
opt WORKFLOW.md exists in repo
WF-->>ORCH: Repo-specific WorkflowDefinition
end
ORCH->>WF: NEW: mergeWorkflows(global, repo, allowedSections)
Note right of WF: MERGE: Overwrites agent/claude/env/hooks<br/>Enforces security boundary (Tracker/Workspace protected)
WF-->>ORCH: Effective Workflow (Merged)
else repo_overrides disabled (Default)
Note over ORCH: Use global Workflow
end
ORCH->>ORCH: NEW: resolveEffectiveConfig(workflow)
Note right of ORCH: Ensures service-level settings<br/>cannot be modified by repo
ORCH->>WS: CHANGED: runBeforeRunHook(effectiveConfig, ...)
WS-->>ORCH: success/fail
ORCH->>AR: CHANGED: Initialize Agent (effectiveConfig)
ORCH->>ORCH: CHANGED: buildPrompt(effectiveWorkflow, ...)
Note right of ORCH: Uses repo's custom Liquid template<br/>if provided
ORCH->>AR: executeAgentTurns(prompt)
loop Agent Steps
AR->>AR: LLM reasoning & Tool calls
end
AR-->>ORCH: run results
ORCH->>WS: CHANGED: runAfterRunHook(effectiveConfig, ...)
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
…erge - Replace shallow merge with recursive deepMerge for nested config sections (fixes claude.settings.attribution loss) - Remove hooks from default allowed override sections (security boundary) - Make prompt_template override respect allowed_sections list - Update all 4 README translations with corrected override rules - Add deep merge test for nested objects
There was a problem hiding this comment.
3 issues found across 9 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.ko.md">
<violation number="1" location="README.ko.md:552">
P2: This table row is now inaccurate: hook overrides are still supported via `repo_overrides.allow: ['hooks']` for `before_run`/`after_run`, so describing `hooks` as never overridable overstates the security boundary.</violation>
</file>
<file name="README.zh-CN.md">
<violation number="1" location="README.zh-CN.md:551">
P2: This table row is inaccurate: repo workflows can still override `hooks.before_run` and `hooks.after_run` when `repo_overrides.allow` includes `hooks`.</violation>
</file>
<file name="README.md">
<violation number="1" location="README.md:579">
P2: The override table is now incorrect: repo workflows can still override `hooks.before_run` and `hooks.after_run`, so documenting `hooks` as entirely non-overridable will mislead operators and repo authors.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
…es tables Hooks are not included in default allowed sections but can be explicitly enabled via repo_overrides.allow: ['hooks']. Updated all 4 README translations to accurately describe this behavior.
|
There was a problem hiding this comment.
0 issues found across 4 files (changes from recent commits).
Requires human review: This PR introduces a significant new feature (per-repo workflow overrides) that modifies core orchestration logic and implements security boundaries, requiring human review.


Summary
WORKFLOW.mddefines global defaults, and individual repositories can supply their ownWORKFLOW.mdto override agent behaviour on a per-repo basisrepo_overrides: truein the service-levelWORKFLOW.mdDesign: Two-Layer Workflow Resolution
Override Rules
agent_prompttoolsmax_turnstrackerhooksworkspaceSecurity Boundary
Service-level sections (
tracker,hooks,workspace) are never overridable by a repository'sWORKFLOW.md. This ensures that credential references, lifecycle hooks, and workspace paths remain under the operator's control regardless of what a target repository provides.Changes
types.ts—RepoOverridesConfiginterfaceworkflow.ts—loadRepoWorkflow()andmergeWorkflows()functionsworkflow.test.ts— 13 new tests for merge logic and repo workflow loadingconfig.ts—parseRepoOverridesSetting()for readingrepo_overridesconfigconfig.test.ts— 7 new tests for repo overrides config parsingorchestrator.ts—resolveEffectiveWorkflow(),resolveEffectiveConfig(); updatedexecuteAgentRun()andrunAgentTurns()to resolve per-issue effective workflowARCHITECTURE.md— Configuration section updated for two-layer workflowREADME.md/README.ko.md/README.ja.md/README.zh-CN.md—repo_overridesschema, override rules, security boundary, and new "Per-Repository Workflow Override" section across all four translationsTest Plan
Summary by cubic
Adds opt‑in per‑repository workflow overrides with recursive deep‑merge and stricter security. A repo’s
WORKFLOW.mdcan adjust agent behavior and the prompt while service‑level settings stay enforced.New Features
repo_overrides(boolean or allow list).agent,claude,env,prompt_template.before_run/after_run; never:tracker,polling,workspace,server.loadRepoWorkflow(),mergeWorkflows(),parseRepoOverridesSetting(), 20 tests, and docs updates acrossREADME*andARCHITECTURE.md.Migration
repo_overrides: truein the globalWORKFLOW.md.repo_overrides: { allow: [agent, claude, env, prompt_template] }. Default remains off.Written for commit 94369f5. Summary will update on new commits.