New to FORGE? Start a free 30-day trial

Multi-Repository Application Commands

Updated on Oct 1, 2026

The frg app commands run workflow commands for an application that spans several repositories. You run them from a parent directory that contains .forge/config/application.toml, and Forge either makes one AI invocation with the context of all repositories or runs a workflow in each repository.

Prerequisites

  • Forge installed with a valid license.
  • A parent directory with .forge/config/application.toml, agents.toml, and toolchain.toml.
  • Child repositories below the parent directory, each with a .forge/config/project.toml.
  • An issue or ticket context: frg config set-issue <id> or frg config set-ticket <id>.

Set up an application

1. Create the application configuration

In the parent directory, run:

bash
frg config init --app

To create toolchain.toml and agents.toml at the same time, combine --app with --issues, --tickets, --scanner, --code, --agent, and --models:

bash
frg config init --app --agent claude_code --issues github_issues --code github

--force can't be combined with --app.

Forge prints the application ID and the line to add to each repository:

Application ID: 32d892fe-e2a8-41b8-aa7d-d018c4942d99
To include repositories in this application, add the following
to each repository's project.toml:

 [project]
 allow_app = "32d892fe-e2a8-41b8-aa7d-d018c4942d99"

Then run frg app discover to find all opted-in repositories.

2. Opt in each repository

Add allow_app with the application ID to the [project] table of each child repository's .forge/config/project.toml:

toml
[project]
# ...
allow_app = "32d892fe-e2a8-41b8-aa7d-d018c4942d99"

To generate project.toml files automatically, use frg app discover --auto.

3. Discover repositories

bash
frg app discover

Forge searches for project.toml files with a matching allow_app and saves the results to the [[repositories]] section of application.toml:

✓ Discovered 2 repositories and saved to application.toml:

 frontend (frontend)
 backend (backend)

If repositories are already configured, Forge lists them and makes no changes. To replace the list, run frg app discover --force.

Generate project configuration automatically

frg app discover --auto creates project.toml for every discovered child repository that doesn't have one. Forge analyzes each repository with AI to fill in metadata such as framework, test framework, and package manager, and sets allow_app to the application ID. Repositories that already have project.toml are skipped.

Before it starts, Forge shows a warning and asks for confirmation (abbreviated):

AI AUTOMATION WARNING
AI analysis will be used to populate project.toml files.

AI hallucinations in project.toml may cause:
 Incorrect framework detection
 Wrong testing framework configuration
 Invalid package manager settings
 Quality issues in dependent workflows

Generated configurations should be reviewed after completion.
Do you want to proceed? [y/N]:

In CI or other non-interactive environments, accept the warning with an environment variable:

bash
FORGE_ACCEPT_AUTO_RISK=true frg app discover --auto

Review the generated files. To correct one repository, run frg config init --interactive in it.

application.toml reference

A file created by frg config init --app and frg app discover:

toml
schema_version = "1.0.0"

[application]
id = "32d892fe-e2a8-41b8-aa7d-d018c4942d99"
name = "shop"
description = "Multi-repository application: shop"

[discovery]
enabled = true
max_depth = 5
exclude = ["node_modules", "target", ".git", "vendor", "dist", "build"]

[[repositories]]
name = "frontend"
path = "frontend"

[[repositories]]
name = "backend"
path = "backend"
KeyDescriptionDefault
schema_versionConfiguration schema version."1.0.0"
[application] idApplication UUID. Child repositories reference it in allow_app.Generated
[application] nameApplication name.Directory name
[application] descriptionApplication description.Generated
[discovery] enabledEnables repository discovery.true
[discovery] max_depthHow many directory levels discovery searches. Must be at least 1.5
[discovery] excludeDirectory names to skip. Patterns can't be empty.node_modules, target, .git, vendor, dist, build
[[repositories]] name, pathRepositories in the application. Written by frg app discover.—
[external_sources] enabledEnables external configuration sources. Individual toggles (agents, toolchain, commands, workflows, telemetry) have no effect when enabled = false.—

Note: Child workflows inherit the application's external_sources setting. Set FORGE_DISABLE_EXTERNAL_CONFIGS to turn off external configuration sources.

Run application commands

bash
frg app <target> <operation> [OPTIONS]
TargetOperations
issuedraft, publish, review, plan, triage, split, ask
backlogcreate, review, rank, ask
codecreate, review, refactor, document, build, test, ask
prdraft, publish, review, merge, ask
docscreate, build, ask
tickettriage, respond, ask, correlate
secaudit, patch, ask
askdefault
rundefault

A typical feature flow:

bash
cd /path/to/app-parent
frg config set-issue 374

frg app issue draft # One issue for the whole feature
frg app issue plan # Plan in each repository
frg app code create # Implement in each repository
frg app code review # Review the feature across repositories
frg app pr draft # Create and describe a PR in each repository
frg app pr review # Review, approve, and merge in each repository

Forge propagates the issue or ticket context to each repository's .forge/context.toml. Each repository gets its own pr_id when its pull request is created.

Execution modes

The app_workflow setting of an operation in commands.toml selects the mode:

  • Direct execution (default, no app_workflow): one AI invocation with the context of all repositories.
  • Workflow execution (app_workflow set): Forge runs the named workflow with frg workflow run in each child repository.

Built-in operations with workflow execution:

CommandWorkflow
frg app issue planissue-to-plan
frg app code createcode-to-review
frg app pr draft, frg app pr publishpr-create-publish
frg app pr review, frg app pr mergepr-review-merge

All other frg app commands use direct execution.

Note: Child workflows run quietly.

Options in direct execution

Direct-execution commands accept the options of the corresponding workflow command, such as --clear, --retry, --auto-retry, --agent, --role, --custom-agent, --model, --print-prompt, --context-file, --context-dir, --edit, and --bypass-safety-checks. Check frg app <target> <operation> --help.

--lite isn't supported for frg app commands:

The --lite flag is not supported for `frg app` commands. Multi-repository operations require detailed analysis for consistency. Use standard mode instead.

Options in workflow execution

OptionDescription
-q, --quietSuppress all output except errors.
--start-from <STEP_NAME>Start the workflow from a specific state instead of the initial state.
--bypass-approvalsSkip approval gates (for CI/automation).
--dry-runValidate the workflow without executing it.

Workflow execution rejects --model, --agent, --role, --context-file, --clear, --edit, --fix, and --lite, even where a command's help lists a modifier. The workflow configuration defines the agent, model, role, and fix behavior. For example:

--model is not supported for workflow execution. Workflow execution uses `frg workflow run` which does not accept model overrides. Model selection is defined in the workflow configuration.

Parallel execution

Workflow execution mode runs in parallel across repositories (default: 3 concurrent workers).

Configure in application.toml:

toml
[application]
max_workers = 5  # Run in up to 5 repositories concurrently

--max-workers controls how many repositories run concurrently; it no longer affects how quickly completion is detected once a workflow finishes (see below).

Monitoring and Completion Detection

While a workflow executes in each child repository, the parent frg app process polls each child's .forge/work/job_<issue-id>/logs/transaction.jsonl every 3 seconds. This transaction log is the single source of truth — it is exactly what frg workflow status reads inside the child repository, so the parent's view and the child's own view agree whenever the parent reaches a terminal state within its detection bound. If the parent instead reports Unknown (see below), no terminal transition was found in that bound; frg workflow status run inside the child repository remains the authoritative live view of what the workflow is actually doing.

Detection bound: once a child's terminal state is durably written to its transaction log, the parent reflects that state within:

  • ~4 seconds in the normal case (one poll interval plus a 1-second terminal check), or
  • ~19 seconds worst case, if the child's own process has already exited before the parent's next poll (a bounded reconciliation window of 5 additional polls).

The parent never waits indefinitely. Every repository ends the run in exactly one of four states:

StateMeaning
DoneThe workflow completed successfully.
FailedThe workflow ended with an error.
Needs ApprovalThe workflow reached an approval gate. When frg app is attached to an interactive terminal, it can be approved or rejected from the parent's own approvals console (see Resolving approval gates below); otherwise, run frg workflow approve inside that child repository, then re-run the frg app command.
UnknownNo terminal transition was found in the child's transaction log within the detection bound. Run frg workflow status inside the named child repository to inspect its own view directly.

Finding Command Output

Execution modeWhere artifacts are written
DirectParent application directory: .forge/work/job_<id>/
WorkflowEach child repository: .forge/work/job_<id>/ inside that repository

After every frg app run, the parent job directory also contains:

  • app_index.toml — machine-readable artifact pointers
  • app_index.md — human-readable summary with repository outcomes and paths

Example repository table:

text
| Repository | Outcome | Job directory | Artifacts | Logs |
| api-service | Done | `../api-service/.forge/work/job_1225` | 4 | `../api-service/.forge/work/job_1225/logs/system.log` |

Read-only: The index contains paths only. Artifacts are owned by the repository that produced them — run frg issue plan --edit (and every other edit command) from inside that repository. Editing anything in the parent folder has no effect on the workflow.

Use frg app status to re-render artifact locations later:

bash
frg app status
frg app status --job 1225
frg app status --paths

frg app status also works for job directories created before the index existed; when no recorded index is present it falls back to scanning the repositories listed in application.toml.

To investigate a failed child repository, open the system.log and transaction.jsonl paths shown in the index, or run frg workflow status inside that repository.

Known limitation: two simultaneous frg app runs for the same issue overwrite each other's index (last writer wins). Each index records run_id and generated_at, so the winning run is still identifiable.

Resolving approval gates

Each repository's approval gate is independent: its own code, message and timeout_seconds. When frg app runs in an interactive terminal, a repository blocked at a gate shows its code inline in the status table (⏸ Needs Approval (code ABCD1234)), and the parent process arms a small line-oriented console the moment at least one repository is pending — no second terminal required.

CommandEffect
lList pending repositories with codes and waiting time
d <sel>Show the gate message and code for the selection
a <sel>Approve the selection
r <sel> [reason]Reject the selection with an optional shared reason
wClose the console; keep polling (out-of-band only)
hHelp

<sel> accepts: omitted (only when exactly one repository is pending), a single index (2), a list (1,3), a range (2-4), a repository name, or all.

Selecting more than one repository previews the batch and asks for y/N confirmation before anything is submitted. A batch collects one approval code (for single-target actions) or skips straight to email (batches use each repository's own discovered code) and one email address for the whole selection, then reports the outcome per repository — approved, rejected, skipped (already resolved), skipped (not pending) or failed — so a partial failure in one repository is never hidden by another repository's success.

Every resolution, whether typed into this console or run out-of-band, goes through the same frg workflow approve / frg workflow reject validation and audit trail, so the two paths can be mixed freely: if another session (or a second terminal) resolves a gate first, the console reports it as resolved elsewhere on its next poll and simply continues.

Per-gate timeout_seconds keeps running while the console is open; a repository that times out leaves Needs Approval on its own, exactly as it would with no console attached.

The console never arms — and behaves exactly as before this feature — when frg app is not attached to an interactive terminal (piped output, --quiet, CI, or FORGE_DISABLE_INLINE_APPROVAL=1). In those cases, resolve gates with frg workflow approve / frg workflow reject from inside the child repository as usual.

See tests/manual_app_inline_approval.md in the repository for manual test procedures covering concurrent gates, batches, out-of-band races, and interrupt/timeout behavior.

PR commands and --start-from

frg app pr draft and frg app pr publish run the same pr-create-publish workflow. It checks whether the repository already has a pr_id in .forge/context.toml, creates a pull request only if needed, and then drafts and publishes the description. Running both commands doesn't create duplicate pull requests.

frg app pr review and frg app pr merge run the same pr-review-merge workflow. It monitors the pull request, reviews it, waits for approval, and merges it. You can re-run either command safely.

Use --start-from with a state name to skip ahead:

bash
# pr-create-publish
frg app pr draft --start-from pr_draft
frg app pr publish --start-from pr_publish

# pr-review-merge
frg app pr merge --start-from await_pr_approval
frg app pr merge --start-from pr_merge

To list a workflow's state names, run frg workflow run <workflow> --list-states. See Workflows.

How agents organize multi-repository output

frg app prompts include an <application> block that lists the repositories. The agent adapts to the architecture it detects:

ContextArchitectureHow work is split
<application> blockMulti-repositoryBy repository
<service> blockMonorepoBy service
NeitherSingle projectBy feature or component

For example, frg app issue split names output files by a slug of each repository path: Forge takes the final directory name, converts it to lowercase, and replaces . and _ with -. A repository at /opt/my.app.web produces issue_my-app-web.md. In a single project, files are named issue_a.md, issue_b.md, and so on.

During workflow execution, Forge propagates the matching issue file to each repository's job directory.

Troubleshooting

No application.toml found. Run 'frg config init --app' to create one.

Cause: The current directory and its parents have no .forge/config/application.toml.

Solution: Run the command from the application's parent directory, or create the file with frg config init --app.

No repositories defined in application.toml. Run 'frg app discover' to scan for repositories or manually add them.

Cause: The [[repositories]] list is empty.

Solution:

  1. Add allow_app to each child repository's project.toml.
  2. Run frg app discover.

No valid repositories available. Check application.toml and ensure repositories exist with correct allow_app UUID.

Cause: The listed repository paths don't exist, or their allow_app doesn't match [application] id.

Solution:

  1. Compare each repository's allow_app with the application ID.
  2. Check the path values in application.toml.
  3. Run frg app discover --force to rebuild the list.

No issue or ticket context set.

Cause: frg app commands need an issue or ticket context.

Solution: Run frg config set-issue <id> or frg config set-ticket <id> in the parent directory.

agents.toml not found. Application execution requires agent configuration.

Cause: The parent directory has no agent configuration. The same applies to toolchain.toml not found. Application execution requires toolchain configuration.

Solution: Run frg config init --agent <agent> or frg config init --issues <tool> --code <tool> in the parent directory.

Cannot run in non-interactive mode. Set FORGE_ACCEPT_AUTO_RISK=true to bypass the warning prompt.

Cause: frg app discover --auto can't show its confirmation prompt, for example in CI.

Solution: Set FORGE_ACCEPT_AUTO_RISK=true for the command, and review the generated files afterward.

Warning: Repository discovery took <n>s. Consider reducing max_depth or adding exclusions.

Cause: Discovery searches a large directory tree.

Solution: Lower [discovery] max_depth, or add large directories to [discovery] exclude.

See Also