Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ agentrc tui

### `agentrc init` — Guided Setup

Interactive or headless repo onboarding — detects your stack and walks through readiness, instructions, and config generation.
Interactive or headless repo onboarding — detects your stack and walks through readiness, instructions, and config generation. For monorepos, auto-detects workspaces and bootstraps `agentrc.config.json` with workspace and area definitions.

### Global Options

Expand Down Expand Up @@ -174,6 +174,31 @@ agentrc readiness --policy ./examples/policies/strict.json,./my-overrides.json

Policies can also be set in `agentrc.config.json` (`{ "policies": ["./my-policy.json"] }`).

### Configuration File

`agentrc.config.json` (repo root or `.github/`) configures areas, workspaces, and policies:

```json
{
"areas": [{ "name": "docs", "applyTo": "docs/**" }],
"workspaces": [
{
"name": "frontend",
"path": "packages/frontend",
"areas": [
{ "name": "app", "applyTo": "app/**" },
{ "name": "shared", "applyTo": ["shared/**", "common/**"] }
]
}
],
"policies": ["./policies/strict.json"]
}
```

- **`areas`** — standalone areas with glob patterns (relative to repo root)
- **`workspaces`** — monorepo sub-projects; each workspace groups areas scoped to a subdirectory. Area `applyTo` patterns are relative to the workspace path. Workspace areas get namespaced names (`frontend/app`) and a `workingDirectory` for scoped eval sessions.
- `agentrc init` auto-detects workspaces (via `.vscode` folders and sibling-area grouping) and bootstraps this file.

> **Security:** Config-sourced policies are restricted to JSON files only — JS/TS module policies must be passed via `--policy`.

See [docs/plugins.md](docs/plugins.md) for the full plugin authoring guide, including imperative TypeScript plugins, lifecycle hooks, and the trust model.
Expand Down
2 changes: 2 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ In `agentrc.config.json`:
}
```

The config file also supports `areas` and `workspaces` for monorepo configuration — see [examples/agentrc.config.json](../examples/agentrc.config.json) for a full example.

Config-sourced policies are restricted to JSON-only for security.

## Scoring
Expand Down
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ agentrc eval agentrc.eval.json --repo /path/to/repo
## Sample eval config

See `agentrc.eval.json` for a starter eval config you can customize.

## Sample project config

See `agentrc.config.json` for an example monorepo configuration with workspaces, areas, and policies.
42 changes: 42 additions & 0 deletions examples/agentrc.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"areas": [
{
"name": "docs",
"applyTo": "docs/**",
"description": "Documentation and guides"
}
],
"workspaces": [
{
"name": "frontend",
"path": "packages/frontend",
"areas": [
{
"name": "app",
"applyTo": "app/**"
},
{
"name": "shared",
"applyTo": ["shared/**", "common/**"],
"description": "Shared libraries"
}
]
},
{
"name": "backend",
"path": "packages/backend",
"areas": [
{
"name": "api",
"applyTo": "src/api/**"
},
{
"name": "workers",
"applyTo": "src/workers/**",
"parentArea": "api"
}
]
}
],
"policies": ["./policies/strict.json"]
}
39 changes: 38 additions & 1 deletion src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import path from "path";

import { checkbox, select } from "@inquirer/prompts";

import { analyzeRepo } from "../services/analyzer";
import { analyzeRepo, detectWorkspaces } from "../services/analyzer";
import type { AgentrcConfig, AgentrcConfigArea } from "../services/analyzer";
import type { AzureDevOpsOrg, AzureDevOpsProject, AzureDevOpsRepo } from "../services/azureDevops";
import {
getAzureDevOpsToken,
Expand Down Expand Up @@ -226,6 +227,42 @@ export async function initCommand(
}
allFiles.push(...genResult.files);

// Bootstrap agentrc.config.json with detected workspaces and standalone areas
if (analysis.areas && analysis.areas.length > 0) {
const configPath = path.join(repoPath, "agentrc.config.json");
const workspaces = await detectWorkspaces(repoPath, analysis.areas);

// Areas already claimed by a workspace (match by path prefix, not name)
const workspacePaths = workspaces.map((ws) => ws.path + "/");

// Standalone areas not inside any workspace
const standaloneAreas: AgentrcConfigArea[] = analysis.areas
.filter((a) => {
if (!a.path) return true;
const rel = path.relative(repoPath, a.path).replace(/\\/gu, "/");
return !workspacePaths.some((prefix) => rel.startsWith(prefix));
})
.map((a) => ({
name: a.name,
applyTo: a.applyTo,
...(a.description ? { description: a.description } : {})
}));

const agentrcConfig: AgentrcConfig = {};
if (workspaces.length > 0) agentrcConfig.workspaces = workspaces;
if (standaloneAreas.length > 0) agentrcConfig.areas = standaloneAreas;

if (agentrcConfig.workspaces || agentrcConfig.areas) {
const configContent = JSON.stringify(agentrcConfig, null, 2) + "\n";
const { wrote } = await safeWriteFile(configPath, configContent, Boolean(options.force));
const rel = path.relative(process.cwd(), configPath);
allFiles.push({ path: rel, action: wrote ? "wrote" : "skipped" });
if (shouldLog(options)) {
process.stderr.write((wrote ? `Wrote ${rel}` : `Skipped ${rel} (exists)`) + "\n");
}
}
}

if (options.json) {
const { ok, status } = deriveFileStatus(allFiles);
const result: CommandResult<{
Expand Down
Loading