Skip to content

feat(workflow): add per-repository workflow override support#120

Open
amondnet wants to merge 3 commits intomainfrom
amondnet/workflow-override
Open

feat(workflow): add per-repository workflow override support#120
amondnet wants to merge 3 commits intomainfrom
amondnet/workflow-override

Conversation

@amondnet
Copy link
Copy Markdown
Contributor

@amondnet amondnet commented Mar 17, 2026

Summary

  • Implements a two-layer workflow resolution system: a service-level WORKFLOW.md defines global defaults, and individual repositories can supply their own WORKFLOW.md to override agent behaviour on a per-repo basis
  • Feature is opt-in — activated by setting repo_overrides: true in the service-level WORKFLOW.md
  • Adds 20 new tests (13 for merge/load logic, 7 for config parsing) alongside the implementation

Design: Two-Layer Workflow Resolution

Service WORKFLOW.md  (global defaults, always loaded)
      +
Repo   WORKFLOW.md  (optional overrides, loaded per issue)
      =
Effective Workflow   (used for each agent run)

Override Rules

Section Overridable?
agent_prompt Yes
tools Yes
max_turns Yes
tracker Never
hooks Never
workspace Never

Security Boundary

Service-level sections (tracker, hooks, workspace) are never overridable by a repository's WORKFLOW.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.tsRepoOverridesConfig interface
  • workflow.tsloadRepoWorkflow() and mergeWorkflows() functions
  • workflow.test.ts — 13 new tests for merge logic and repo workflow loading
  • config.tsparseRepoOverridesSetting() for reading repo_overrides config
  • config.test.ts — 7 new tests for repo overrides config parsing
  • orchestrator.tsresolveEffectiveWorkflow(), resolveEffectiveConfig(); updated executeAgentRun() and runAgentTurns() to resolve per-issue effective workflow
  • ARCHITECTURE.md — Configuration section updated for two-layer workflow
  • README.md / README.ko.md / README.ja.md / README.zh-CN.mdrepo_overrides schema, override rules, security boundary, and new "Per-Repository Workflow Override" section across all four translations

Test Plan

  • All 589 existing tests pass
  • 20 new tests pass (workflow merge logic + config parsing)
  • Lint passes with no warnings
  • No TypeScript type errors

Summary by cubic

Adds opt‑in per‑repository workflow overrides with recursive deep‑merge and stricter security. A repo’s WORKFLOW.md can adjust agent behavior and the prompt while service‑level settings stay enforced.

  • New Features

    • Two-layer workflow with repo_overrides (boolean or allow list).
    • Recursive deep‑merge; default overridable: agent, claude, env, prompt_template.
    • Hooks override is opt‑in and limited to before_run/after_run; never: tracker, polling, workspace, server.
    • Orchestrator resolves an effective workflow per issue and preserves service-level settings; added loadRepoWorkflow(), mergeWorkflows(), parseRepoOverridesSetting(), 20 tests, and docs updates across README* and ARCHITECTURE.md.
  • Migration

    • Enable with repo_overrides: true in the global WORKFLOW.md.
    • Optionally restrict with repo_overrides: { allow: [agent, claude, env, prompt_template] }. Default remains off.

Written for commit 94369f5. Summary will update on new commits.

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
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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

  • Per-Repository Workflow Overrides: Introduced a two-layer workflow resolution system allowing individual repositories to override agent behavior and prompt templates via their own WORKFLOW.md files. This feature is opt-in, enabled by setting repo_overrides: true in the service-level WORKFLOW.md.
  • Security Boundary Enforcement: Ensured that service-level sections such as tracker, hooks (specifically after_create, before_remove), and workspace are never overridable by repository-level WORKFLOW.md files, maintaining operator control over critical configurations.
  • Workflow Resolution Logic: Implemented new functions (loadRepoWorkflow, mergeWorkflows, parseRepoOverridesSetting) and updated the orchestrator to dynamically resolve an effective workflow and configuration per issue, merging allowed repository-specific settings over global defaults.
  • Comprehensive Testing and Documentation: Added 20 new tests covering workflow merge logic and configuration parsing, and updated ARCHITECTURE.md and all README.md translations (English, Japanese, Korean, Chinese) to reflect the new two-layer workflow system, override rules, and security considerations.
Changelog
  • ARCHITECTURE.md
    • Updated description of workflow.ts to include repo override merge functionality.
    • Revised the 'Configuration' section to detail the new two-layer workflow resolution, including global and repo WORKFLOW.md files, merge semantics, and live reload behavior.
  • README.ja.md
    • Added new sections for 'リポジトリごとのワークフローオーバーライド' (Per-Repository Workflow Override), detailing its mechanism, override rules, and examples.
    • Updated the WORKFLOW.md configuration schema to include the repo_overrides setting.
  • README.ko.md
    • Added new sections for '저장소별 워크플로우 오버라이드' (Per-Repository Workflow Override), detailing its mechanism, override rules, and examples.
    • Updated the WORKFLOW.md configuration schema to include the repo_overrides setting.
  • README.md
    • Added new sections for 'Per-Repository Workflow Override', detailing its mechanism, override rules, and examples.
    • Updated the WORKFLOW.md configuration schema to include the repo_overrides setting.
  • README.zh-CN.md
    • Added new sections for '仓库级工作流覆盖' (Per-Repository Workflow Override), detailing its mechanism, override rules, and examples.
    • Updated the WORKFLOW.md configuration schema to include the repo_overrides setting.
  • apps/work-please/src/config.test.ts
    • Imported parseRepoOverridesSetting for testing.
    • Added a new test suite for parseRepoOverridesSetting to verify its behavior with various inputs, including absent, boolean, and object values for repo_overrides, and filtering of disallowed sections.
  • apps/work-please/src/config.ts
    • Imported RepoOverridesConfig type.
    • Defined OVERRIDABLE_SECTIONS and DEFAULT_ALLOWED_SECTIONS constants.
    • Added parseRepoOverridesSetting function to interpret the repo_overrides configuration, determining if overrides are enabled and which sections are allowed.
  • apps/work-please/src/orchestrator.ts
    • Imported RepoOverridesConfig, loadRepoWorkflow, mergeWorkflows, and parseRepoOverridesSetting.
    • Added repoOverridesConfig property to the Orchestrator class.
    • Initialized repoOverridesConfig during orchestrator setup and workflow reload.
    • Modified executeAgentRun to resolve an effectiveWorkflow and effectiveConfig based on global and repository-level WORKFLOW.md files before running hooks and agent turns.
    • Updated runAgentTurns to accept and use the effectiveWorkflow and effectiveConfig.
    • Added resolveEffectiveWorkflow method to load and merge repository workflows if enabled.
    • Added resolveEffectiveConfig method to build a service configuration from an effective workflow, preserving service-level sections from the global config.
  • apps/work-please/src/types.ts
    • Defined the RepoOverridesConfig interface to specify whether repository overrides are enabled and which sections are allowed.
  • apps/work-please/src/workflow.test.ts
    • Imported necessary modules for file system operations and WorkflowDefinition type.
    • Imported loadRepoWorkflow and mergeWorkflows for testing.
    • Added a new test suite for mergeWorkflows to verify correct merging behavior, including handling of null overrides, allowed/disallowed sections, prompt template replacement, deep merging, additive environment variables, specific hook merging, and immutability of the base workflow.
    • Added a new test suite for loadRepoWorkflow to verify loading of WORKFLOW.md from a workspace path, including cases where the file is missing or invalid.
  • apps/work-please/src/workflow.ts
    • Imported createLogger and initialized a logger for the module.
    • Added HOOK_OVERRIDABLE_KEYS constant to specify which hooks can be overridden.
    • Added loadRepoWorkflow function to read and parse a WORKFLOW.md file from a given workspace path, returning null if not found or invalid.
    • Added mergeWorkflows function to combine a base workflow with a repository override, respecting allowed sections and handling special cases like hooks and prompt templates.
    • Added isPlainObject and deepClone utility functions to support the merging logic.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 30 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
apps/work-please/src/orchestrator.ts 33.33% 28 Missing ⚠️
apps/work-please/src/workflow.ts 96.72% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

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.

Comment thread apps/work-please/src/workflow.ts
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

10 issues found across 11 files

Confidence score: 2/5

  • There is a concrete security-boundary risk in apps/work-please/src/orchestrator.ts and apps/work-please/src/workflow.ts: repo-local WORKFLOW.md can override hooks.before_run/hooks.after_run, enabling repository-controlled shell execution that should remain service-controlled.
  • apps/work-please/src/orchestrator.ts also appears to pass fully merged repo config into runtime loading, making repo claude/env keys effective beyond documented overrides and increasing unintended behavior/regression risk.
  • apps/work-please/src/config.ts and apps/work-please/src/config.test.ts suggest policy/implementation drift (prompt_template allowlist 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, ...)
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/work-please/src/orchestrator.ts
Comment thread apps/work-please/src/workflow.ts
Comment thread apps/work-please/src/orchestrator.ts
Comment thread apps/work-please/src/config.test.ts Outdated
Comment thread README.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread README.zh-CN.md Outdated
Comment thread README.ja.md
Comment thread apps/work-please/src/config.ts
Comment thread README.ko.md Outdated
@amondnet amondnet self-assigned this Mar 17, 2026
…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
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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.

Comment thread README.ko.md Outdated
Comment thread README.zh-CN.md Outdated
Comment thread README.md Outdated
…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.
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant