@ai-outfitter/outfitter 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -23
- package/code/pi-extension/src/outfitter-runtime-extension.js +45 -6
- package/dist/cli/OutfitterCli.js +2 -7
- package/dist/cli/OutfitterCli.js.map +1 -1
- package/dist/cli/commands/PiRuntimeLaunch.d.ts +14 -4
- package/dist/cli/commands/PiRuntimeLaunch.js +23 -14
- package/dist/cli/commands/PiRuntimeLaunch.js.map +1 -1
- package/dist/cli/commands/RunAgentCommand.js +7 -3
- package/dist/cli/commands/RunAgentCommand.js.map +1 -1
- package/dist/composer/Composer.js +1 -0
- package/dist/composer/Composer.js.map +1 -1
- package/dist/composer/Composition.d.ts +2 -0
- package/dist/resolver/AgentDefinition.d.ts +2 -0
- package/dist/resolver/AgentDefinition.js +2 -0
- package/dist/resolver/AgentDefinition.js.map +1 -1
- package/dist/schemas/agent.schema.json +1 -0
- package/dist/version/OutfitterVersion.d.ts +1 -0
- package/dist/version/OutfitterVersion.js +8 -0
- package/dist/version/OutfitterVersion.js.map +1 -0
- package/docs/documentation/README.md +46 -31
- package/docs/documentation/actions.md +3 -1
- package/docs/documentation/agents.md +5 -0
- package/docs/documentation/concepts.md +6 -6
- package/docs/documentation/conventions.md +55 -0
- package/docs/documentation/in-cluster.md +35 -0
- package/docs/documentation/recurring-runs.md +27 -0
- package/docs/documentation/subagents.md +16 -5
- package/docs/documentation/usecases/flaky-test-postmortems.md +20 -0
- package/docs/documentation/usecases/grafana-alert-investigator.md +18 -0
- package/docs/documentation/usecases/resident-agents.md +36 -0
- package/docs/documentation/usecases/self-improving-skills.md +19 -0
- package/docs/documentation/usecases/shared-conventions.md +47 -0
- package/package.json +1 -1
- package/src/schemas/agent.schema.json +1 -0
package/README.md
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
# Outfitter
|
|
2
2
|
|
|
3
|
-
Outfitter is the toolchain for
|
|
3
|
+
Outfitter is the toolchain for [`.agents`](./docs/documentation/concepts.md#the-agents-protocol): it resolves agent configuration from local and remote `.agents` trees, composes agents, skills, and knowledge by slug, and launches the result through wrapped agent CLIs like [`pi`](https://github.com/earendil-works/pi-coding-agent) and Claude Code.
|
|
4
4
|
|
|
5
5
|
Outfitter does not own a configuration format. Your `.agents/` directory is the source of truth — useful without Outfitter, committed and reviewed like any other code.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Your agent setup is configuration: prompts, skills, MCP servers, model choices, permissions. Left alone it lives per tool and per laptop, gets pasted between repos, and drifts. Outfitter treats it like the rest of your infrastructure — layered, composed by slug, pinned by SHA, reviewed through pull requests.
|
|
10
|
+
|
|
11
|
+
That turns one person's improvement into everyone's default. On Monday a platform engineer writes a `grafana-alert-investigate` skill in their own `~/.agents` tree and uses it at their desk. By Friday it is merged into the org catalog, pinned by SHA, and selected by slug from an agent that also runs on a CI schedule and in the cluster. Nobody else configured anything — their next run composes the new skill, and it costs their context window one line of routing metadata until it activates.
|
|
12
|
+
|
|
13
|
+
Two conventions do most of that work:
|
|
14
|
+
|
|
15
|
+
- Iterate on it in your own `~/.agents` against real work, then share it by pull request — to the project, your org's catalog, or a community catalog. Everyone composes the shared version back by slug, and anything they need different they override in their own layer instead of copying. See [Conventions](./docs/documentation/conventions.md).
|
|
16
|
+
|
|
17
|
+
- The same composition runs everywhere work happens: interactively at your desk, [in GitHub Actions](./docs/documentation/actions.md) on any trigger, as [recurring loops](./docs/documentation/recurring-runs.md) — locally, on a CI cron, or on a cluster schedule — and as resident or job-based agents [in Kubernetes](./docs/documentation/in-cluster.md). Surface availability varies by release; each page notes its status.
|
|
18
|
+
|
|
19
|
+
For the full argument, read the [Philosophy](./docs/philosophy.md).
|
|
8
20
|
|
|
9
21
|
## Quick start
|
|
10
22
|
|
|
@@ -64,30 +76,28 @@ Managed porting and persistent harness symlinks are deferred to
|
|
|
64
76
|
commands/ # slash commands
|
|
65
77
|
```
|
|
66
78
|
|
|
67
|
-
Layers merge by ID: `<project>/.agents/` over `~/.agents/` over pinned remote [catalogs](./docs/documentation/catalogs.md). An [agent](./docs/documentation/agents.md) carries both its identity and its loadout — an [agent profile](./docs/documentation/profiles.md) — and is what you run; a [persona](./docs/documentation/personas.md) is a review convention layered on a base agent; a [subagent](./docs/documentation/subagents.md) is an agent a run delegates to,
|
|
68
|
-
|
|
69
|
-
Agents can also run headlessly in GitHub Actions via [`ai-outfitter/actions`](https://github.com/ai-outfitter/actions).
|
|
79
|
+
Layers merge by ID: `<project>/.agents/` over `~/.agents/` over pinned remote [catalogs](./docs/documentation/catalogs.md). An [agent](./docs/documentation/agents.md) carries both its identity and its loadout — an [agent profile](./docs/documentation/profiles.md) — and is what you run; a [persona](./docs/documentation/personas.md) is a review convention layered on a base agent; a [subagent](./docs/documentation/subagents.md) is an agent a run delegates to, across [four delegation boundaries](./docs/documentation/subagents.md#the-four-delegation-boundaries) from an in-session helper to a Kubernetes Job.
|
|
70
80
|
|
|
71
81
|
## Documentation
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- [
|
|
76
|
-
- [Agents](./docs/documentation/agents.md) · [
|
|
77
|
-
- [
|
|
78
|
-
- [
|
|
79
|
-
- [
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- [
|
|
84
|
-
- [
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
- [
|
|
89
|
-
- [
|
|
90
|
-
- [
|
|
83
|
+
The [documentation index](./docs/documentation/README.md) follows the same arc — set up your own, understand the pieces, share across your org, automate more surfaces, contribute back:
|
|
84
|
+
|
|
85
|
+
- **Start:** [Getting started](./docs/documentation/getting-started.md) · [First-time CLI agent users](./docs/documentation/first-time-cli-agent-users.md) · [Switching to Outfitter](./docs/documentation/switching-to-outfitter.md)
|
|
86
|
+
- **Understand:** [Concepts](./docs/documentation/concepts.md) · [Agents](./docs/documentation/agents.md) · [Skills](./docs/documentation/skills.md) · [Personas](./docs/documentation/personas.md) · [Subagents and delegation](./docs/documentation/subagents.md)
|
|
87
|
+
- **Share:** [Catalogs](./docs/documentation/catalogs.md) · [Conventions](./docs/documentation/conventions.md) · [Organization catalog](./docs/documentation/usecases/organization-profile-catalog.md) · [Best practices](./docs/documentation/best-practices.md)
|
|
88
|
+
- **Automate:** [GitHub Actions](./docs/documentation/actions.md) · [Recurring runs](./docs/documentation/recurring-runs.md) · [In-cluster agents](./docs/documentation/in-cluster.md) · [Hooks](./docs/documentation/hooks.md) · [State persistence](./docs/documentation/state.md)
|
|
89
|
+
- **Reference:** [CLI](./docs/documentation/cli.md) · [Settings](./docs/documentation/settings.md) · [Adapter support matrix](./docs/documentation/support-matrix.md) · [Philosophy](./docs/philosophy.md)
|
|
90
|
+
|
|
91
|
+
Use cases, story first:
|
|
92
|
+
|
|
93
|
+
- [Shared conventions without duplication](./docs/documentation/usecases/shared-conventions.md)
|
|
94
|
+
- [Flaky-test post-mortems in CI](./docs/documentation/usecases/flaky-test-postmortems.md)
|
|
95
|
+
- [Grafana alert investigations in-cluster](./docs/documentation/usecases/grafana-alert-investigator.md)
|
|
96
|
+
- [Self-improving skills](./docs/documentation/usecases/self-improving-skills.md)
|
|
97
|
+
- [Resident agents: a researcher wiki](./docs/documentation/usecases/resident-agents.md)
|
|
98
|
+
- [Persona reviews](./docs/documentation/usecases/persona-reviews.md)
|
|
99
|
+
- [Organization catalog](./docs/documentation/usecases/organization-profile-catalog.md)
|
|
100
|
+
- [Engineering catalog](./docs/documentation/usecases/engineering.md)
|
|
91
101
|
|
|
92
102
|
For local development, repository structure, and release workflow details, see [Contributing](./CONTRIBUTING.md).
|
|
93
103
|
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { VERSION as PI_VERSION } from '@earendil-works/pi-coding-agent';
|
|
1
2
|
import { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
3
|
|
|
4
|
+
const OUTFITTER_ACTIVE_PROFILE = '__OUTFITTER_ACTIVE_PROFILE__';
|
|
5
|
+
const OUTFITTER_VERSION = '__OUTFITTER_VERSION__';
|
|
6
|
+
|
|
3
7
|
// Outfitter runtime extension. Unlike the setup walkthrough extension
|
|
4
|
-
// (outfitter-extension.js), this file is loaded into the real profile pi session.
|
|
5
|
-
//
|
|
6
|
-
// no models available, it offers to connect one and delegates
|
|
7
|
-
// persists credentials in pi's own agent directory and selects
|
|
8
|
+
// (outfitter-extension.js), this file is loaded into the real profile pi session. It restores the
|
|
9
|
+
// Outfitter + pi header and active-profile status, plus the original "no provider connected yet"
|
|
10
|
+
// sign-in prompt: when pi starts with no models available, it offers to connect one and delegates
|
|
11
|
+
// to pi's native /login command, which persists credentials in pi's own agent directory and selects
|
|
12
|
+
// a default model in-session.
|
|
8
13
|
//
|
|
9
14
|
// The setup pi stays deliberately model-free and MUST NOT open /login (OFTR-010.1.4); that is why
|
|
10
|
-
// the auto-login lives here instead.
|
|
11
|
-
//
|
|
15
|
+
// the auto-login lives here instead. The CLI stamps profile and Outfitter-version metadata into a
|
|
16
|
+
// per-run copy before loading it via --extension. PI_VERSION comes from the running pi package.
|
|
12
17
|
|
|
13
18
|
export default function outfitterRuntime(pi) {
|
|
14
19
|
let loginSubmitted = false;
|
|
@@ -72,10 +77,44 @@ export default function outfitterRuntime(pi) {
|
|
|
72
77
|
|
|
73
78
|
pi.on('session_start', async (event, ctx) => {
|
|
74
79
|
if (ctx.mode !== 'tui') return;
|
|
80
|
+
setRuntimeHeader(ctx);
|
|
81
|
+
updateProfileStatus(ctx);
|
|
75
82
|
if (event.reason === 'startup') await openLoginIfNoModels(ctx);
|
|
76
83
|
});
|
|
77
84
|
}
|
|
78
85
|
|
|
86
|
+
const setRuntimeHeader = (ctx) => {
|
|
87
|
+
ctx.ui.setHeader((_tui, theme) => {
|
|
88
|
+
let cachedWidth;
|
|
89
|
+
let cachedLines;
|
|
90
|
+
return {
|
|
91
|
+
render: (width) => {
|
|
92
|
+
const maxWidth = typeof width === 'number' && width > 0 ? width : 120;
|
|
93
|
+
if (cachedLines === undefined || cachedWidth !== maxWidth) {
|
|
94
|
+
const line =
|
|
95
|
+
theme.bold(theme.fg('accent', 'Outfitter')) + theme.fg('dim', ` v${OUTFITTER_VERSION} + pi v${PI_VERSION}`);
|
|
96
|
+
cachedLines = [visibleWidth(line) > maxWidth ? truncateToWidth(line, maxWidth) : line];
|
|
97
|
+
cachedWidth = maxWidth;
|
|
98
|
+
}
|
|
99
|
+
return cachedLines;
|
|
100
|
+
},
|
|
101
|
+
invalidate: () => {
|
|
102
|
+
cachedWidth = undefined;
|
|
103
|
+
cachedLines = undefined;
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const updateProfileStatus = (ctx) => {
|
|
110
|
+
// Stays a string when the source asset is loaded without Outfitter stamping and is undefined
|
|
111
|
+
// when a caller intentionally attaches the extension without a resolved profile.
|
|
112
|
+
if (typeof OUTFITTER_ACTIVE_PROFILE !== 'object' || OUTFITTER_ACTIVE_PROFILE === null) return;
|
|
113
|
+
const name = OUTFITTER_ACTIVE_PROFILE.label ?? OUTFITTER_ACTIVE_PROFILE.id;
|
|
114
|
+
if (!name) return;
|
|
115
|
+
ctx.ui.setStatus('outfitter-profile', ctx.ui.theme.fg('muted', 'profile: ' + name));
|
|
116
|
+
};
|
|
117
|
+
|
|
79
118
|
// Renders a described-option picker identical to the setup walkthrough's, so the runtime sign-in
|
|
80
119
|
// prompt matches the rest of the Outfitter UI. Falls back to a plain label list when pi does not
|
|
81
120
|
// support custom UI, then resolves the chosen label back to its item value.
|
package/dist/cli/OutfitterCli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Assembles the top-level Outfitter Commander program from command objects.
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
2
|
import { Command } from 'commander';
|
|
3
|
+
import { readOutfitterVersion } from '../version/OutfitterVersion.js';
|
|
4
4
|
import { createDumpCommand } from './commands/DumpCommand.js';
|
|
5
5
|
import { createListCommand } from './commands/ListCommand.js';
|
|
6
6
|
import { createRunAgentCommand } from './commands/RunAgentCommand.js';
|
|
@@ -18,15 +18,10 @@ export const createOutfitterProgram = (commands = createDefaultCommands()) => {
|
|
|
18
18
|
program
|
|
19
19
|
.name('outfitter')
|
|
20
20
|
.description('Resolve, compose, and launch .agents agents in pi, Claude Code, and future harnesses.')
|
|
21
|
-
.version(
|
|
21
|
+
.version(readOutfitterVersion());
|
|
22
22
|
for (const command of commands) {
|
|
23
23
|
command.register(program);
|
|
24
24
|
}
|
|
25
25
|
return program;
|
|
26
26
|
};
|
|
27
|
-
const readPackageVersion = () => {
|
|
28
|
-
const packageJsonPath = new URL('../../package.json', import.meta.url);
|
|
29
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
30
|
-
return packageJson.version;
|
|
31
|
-
};
|
|
32
27
|
//# sourceMappingURL=OutfitterCli.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OutfitterCli.js","sourceRoot":"","sources":["../../src/cli/OutfitterCli.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"OutfitterCli.js","sourceRoot":"","sources":["../../src/cli/OutfitterCli.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAoB,EAAE,CAAC;IAC1D,qBAAqB,EAAE;IACvB,kBAAkB,EAAE;IACpB,iBAAiB,EAAE;IACnB,qBAAqB,EAAE;IACvB,iBAAiB,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAqC,qBAAqB,EAAE,EAAW,EAAE;IAC9G,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,WAAW,CAAC;SACjB,WAAW,CAAC,uFAAuF,CAAC;SACpG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAEnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import type { AgentLaunchPlan } from '../../projection/Projection.js';
|
|
2
|
+
export interface PiRuntimeProfileIdentity {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly label?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PiRuntimeExtensionInput {
|
|
7
|
+
readonly outfitterVersion: string;
|
|
8
|
+
readonly profile?: PiRuntimeProfileIdentity;
|
|
9
|
+
readonly rootDirectory: string;
|
|
10
|
+
}
|
|
2
11
|
export declare const isNonInteractivePiLaunch: (args: readonly string[]) => boolean;
|
|
12
|
+
/** Stamps per-run identity metadata into the runtime extension source. */
|
|
13
|
+
export declare const createPiRuntimeExtensionContent: (input: Omit<PiRuntimeExtensionInput, "rootDirectory">) => string;
|
|
3
14
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* run. Non-pi and non-interactive launches are returned unchanged.
|
|
15
|
+
* Materializes and prepends `--extension <runtime>` to an interactive pi launch. Non-pi and
|
|
16
|
+
* non-interactive launches are returned unchanged.
|
|
7
17
|
*/
|
|
8
|
-
export declare const attachPiRuntimeExtension: (plan: AgentLaunchPlan) => AgentLaunchPlan;
|
|
18
|
+
export declare const attachPiRuntimeExtension: (plan: AgentLaunchPlan, input: PiRuntimeExtensionInput) => AgentLaunchPlan;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// Attaches the Outfitter runtime pi extension to interactive profile launches. The extension
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
import {
|
|
1
|
+
// Attaches the Outfitter runtime pi extension to interactive profile launches. The extension owns
|
|
2
|
+
// the Outfitter + pi header, active-profile status, and "connect a model provider" sign-in prompt.
|
|
3
|
+
// Non-interactive pi launches (--print, --export, --mode json|print|rpc, …) are left untouched so
|
|
4
|
+
// scripted runs never prompt, and non-pi harnesses pass through unchanged.
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
8
|
const nonInteractivePiLaunchFlags = new Set(['--print', '-p', '--export', '--list-models']);
|
|
9
9
|
const nonInteractivePiModes = new Set(['json', 'print', 'rpc']);
|
|
@@ -30,18 +30,27 @@ const resolveRuntimeExtensionPath = () => {
|
|
|
30
30
|
return packagePath;
|
|
31
31
|
return undefined;
|
|
32
32
|
};
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
* a no-op whenever a model is already available, so it is safe to attach to every interactive pi
|
|
36
|
-
* run. Non-pi and non-interactive launches are returned unchanged.
|
|
37
|
-
*/
|
|
38
|
-
export const attachPiRuntimeExtension = (plan) => {
|
|
39
|
-
if (plan.command !== 'pi' || isNonInteractivePiLaunch(plan.args))
|
|
40
|
-
return plan;
|
|
33
|
+
/** Stamps per-run identity metadata into the runtime extension source. */
|
|
34
|
+
export const createPiRuntimeExtensionContent = (input) => {
|
|
41
35
|
const extensionPath = resolveRuntimeExtensionPath();
|
|
42
36
|
/* v8 ignore next -- defensive: the runtime extension ships with the package, so it resolves in practice. */
|
|
43
37
|
if (extensionPath === undefined)
|
|
38
|
+
throw new Error('Outfitter runtime extension was not found.');
|
|
39
|
+
return readFileSync(extensionPath, 'utf8')
|
|
40
|
+
.replace(/["']__OUTFITTER_VERSION__["']/gu, JSON.stringify(input.outfitterVersion))
|
|
41
|
+
.replace(/["']__OUTFITTER_ACTIVE_PROFILE__["']/gu, JSON.stringify(input.profile) ?? 'undefined');
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Materializes and prepends `--extension <runtime>` to an interactive pi launch. Non-pi and
|
|
45
|
+
* non-interactive launches are returned unchanged.
|
|
46
|
+
*/
|
|
47
|
+
export const attachPiRuntimeExtension = (plan, input) => {
|
|
48
|
+
if (plan.command !== 'pi' || isNonInteractivePiLaunch(plan.args))
|
|
44
49
|
return plan;
|
|
50
|
+
const extensionDirectory = join(input.rootDirectory, '.outfitter');
|
|
51
|
+
const extensionPath = join(extensionDirectory, 'outfitter-runtime-extension.js');
|
|
52
|
+
mkdirSync(extensionDirectory, { recursive: true });
|
|
53
|
+
writeFileSync(extensionPath, createPiRuntimeExtensionContent(input));
|
|
45
54
|
return { ...plan, args: ['--extension', extensionPath, ...plan.args] };
|
|
46
55
|
};
|
|
47
56
|
//# sourceMappingURL=PiRuntimeLaunch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PiRuntimeLaunch.js","sourceRoot":"","sources":["../../../src/cli/commands/PiRuntimeLaunch.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"PiRuntimeLaunch.js","sourceRoot":"","sources":["../../../src/cli/commands/PiRuntimeLaunch.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@ import { projectComposition } from '../../projection/ProjectHarness.js';
|
|
|
12
12
|
import { findResource } from '../../resolver/Resource.js';
|
|
13
13
|
import { resolveEffectiveSet } from '../../resolver/ResolverContext.js';
|
|
14
14
|
import { HARNESSES } from '../../settings/Settings.js';
|
|
15
|
+
import { readOutfitterVersion } from '../../version/OutfitterVersion.js';
|
|
15
16
|
import { attachPiRuntimeExtension } from './PiRuntimeLaunch.js';
|
|
16
17
|
import { resolveHomeDirectory, resolveProjectDirectory } from './ProcessDefaults.js';
|
|
17
18
|
import { runSetup } from './SetupCommand.js';
|
|
@@ -123,9 +124,12 @@ export const executeRunAgentCommand = async (input) => {
|
|
|
123
124
|
// Emit setup notices and warnings before launch so they precede the pi session on the terminal.
|
|
124
125
|
const messages = [...setupMessages, ...warnings];
|
|
125
126
|
emit(messages);
|
|
126
|
-
// Attach the Outfitter runtime extension
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
// Attach the Outfitter runtime UI and sign-in extension to interactive pi sessions.
|
|
128
|
+
const launch = attachPiRuntimeExtension(projection.launch, {
|
|
129
|
+
outfitterVersion: readOutfitterVersion(),
|
|
130
|
+
profile: { id: agentSlug, label: composed.plan.identity.label },
|
|
131
|
+
rootDirectory,
|
|
132
|
+
});
|
|
129
133
|
const exitCode = await launchWithCredentialPersistence(input, harness, rootDirectory, launch);
|
|
130
134
|
return { launchPlan: launch, exitCode, messages };
|
|
131
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunAgentCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/RunAgentCommand.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAW,MAAM,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,iBAAiB,GAClB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAE1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"RunAgentCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/RunAgentCommand.ts"],"names":[],"mappings":"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"}
|
|
@@ -62,6 +62,7 @@ export const compose = (set, agentSlug) => {
|
|
|
62
62
|
systemPrompt: readRootFile(set, 'system-prompt.md'),
|
|
63
63
|
sharedContext: readRootFile(set, 'agents.md'),
|
|
64
64
|
agentBody: definition.body,
|
|
65
|
+
label: definition.label,
|
|
65
66
|
description: definition.description,
|
|
66
67
|
},
|
|
67
68
|
loadout: composeLoadout(set, agentSlug, definition.loadout, warnings),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../src/composer/Composer.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../src/composer/Composer.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@ export interface ComposedIdentity {
|
|
|
7
7
|
readonly sharedContext?: string;
|
|
8
8
|
/** The selected agent's `agent.md` markdown body. */
|
|
9
9
|
readonly agentBody: string;
|
|
10
|
+
/** Human-readable profile name for interactive harness UI. */
|
|
11
|
+
readonly label?: string;
|
|
10
12
|
readonly description?: string;
|
|
11
13
|
}
|
|
12
14
|
/** A loadout with its slug references resolved against the effective set. */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Loadout } from './Resource.js';
|
|
2
2
|
export interface AgentDefinition {
|
|
3
3
|
readonly name: string;
|
|
4
|
+
/** Human-readable profile name shown in interactive harness UI. */
|
|
5
|
+
readonly label?: string;
|
|
4
6
|
readonly description?: string;
|
|
5
7
|
/** Markdown body after the frontmatter — the agent's identity prose. */
|
|
6
8
|
readonly body: string;
|
|
@@ -37,6 +37,7 @@ export const splitFrontmatter = (content) => {
|
|
|
37
37
|
};
|
|
38
38
|
const asStringArray = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : [];
|
|
39
39
|
const asString = (value) => (typeof value === 'string' ? value : undefined);
|
|
40
|
+
const readMarkdownHeading = (body) => /^#\s+(.+)$/mu.exec(body)?.[1]?.trim();
|
|
40
41
|
const loadoutFromRecord = (record) => {
|
|
41
42
|
const tools = record.tools;
|
|
42
43
|
return {
|
|
@@ -105,6 +106,7 @@ export const parseAgentDefinition = (content, configPaths, agentPath) => {
|
|
|
105
106
|
}
|
|
106
107
|
return {
|
|
107
108
|
name: frontmatter.record.name,
|
|
109
|
+
label: asString(frontmatter.record.label)?.trim() || readMarkdownHeading(frontmatter.body),
|
|
108
110
|
description: asString(frontmatter.record.description),
|
|
109
111
|
body: frontmatter.body,
|
|
110
112
|
loadout: loadoutFromRecord(merged),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentDefinition.js","sourceRoot":"","sources":["../../src/resolver/AgentDefinition.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentDefinition.js","sourceRoot":"","sources":["../../src/resolver/AgentDefinition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const readOutfitterVersion: () => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Reads the installed Outfitter package version for CLI output and runtime branding.
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
export const readOutfitterVersion = () => {
|
|
4
|
+
const packageJsonPath = new URL('../../package.json', import.meta.url);
|
|
5
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
6
|
+
return packageJson.version;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=OutfitterVersion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OutfitterVersion.js","sourceRoot":"","sources":["../../src/version/OutfitterVersion.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAW,EAAE;IAC/C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAiC,CAAC;IAEtG,OAAO,WAAW,CAAC,OAAO,CAAC;AAC7B,CAAC,CAAC"}
|
|
@@ -1,45 +1,60 @@
|
|
|
1
1
|
# Outfitter documentation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Outfitter lays out conventions for iterating on and sharing agent configuration — agent profiles, skills, and loadouts. The docs follow that arc: **set up** your own, **understand** the pieces, **share** them across projects and your org, **automate** them on more surfaces, then contribute back. Each page keeps to one concept and links onward when you need the next one, so nothing here has to be read up front.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Start (you)
|
|
6
6
|
|
|
7
|
-
- [Getting started](./getting-started.md)
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
7
|
+
- [Getting started](./getting-started.md) — install, first run, default agent.
|
|
8
|
+
- [First-time CLI agent users](./first-time-cli-agent-users.md) — new to agent CLIs entirely.
|
|
9
|
+
- [Switching to Outfitter](./switching-to-outfitter.md) — adopt from an existing agent-CLI setup.
|
|
10
|
+
- [Porting a Claude Code setup](./porting-claude.md) — `~/.claude` into `~/.agents/` with symlinks back.
|
|
11
|
+
|
|
12
|
+
## Understand (the model)
|
|
13
|
+
|
|
14
|
+
- [Concepts](./concepts.md) — resolve → compose → adapt; layers and precedence.
|
|
15
|
+
- [Agents](./agents.md) — the `agents/<id>/agent.md` resource and its loadout — what you run.
|
|
16
|
+
- [Agent profiles](./profiles.md) — why an agent and its loadout _is_ the profile.
|
|
17
|
+
- [Skills](./skills.md) — capability packages with progressive disclosure, references, and routing.
|
|
18
|
+
- [Personas](./personas.md) — the base-agent-plus-persona-documents review convention.
|
|
19
|
+
- [Subagents and delegation](./subagents.md) — the four delegation boundaries, from in-session helpers to Kubernetes Jobs.
|
|
20
|
+
- [Settings](./settings.md) — scopes, schema, and the flat `settings.local.yml` override file.
|
|
21
|
+
- [Tasks](./tasks.md) — placeholder for a separate upcoming RFC.
|
|
22
|
+
|
|
23
|
+
## Share (project → org → community)
|
|
11
24
|
|
|
12
|
-
|
|
25
|
+
- [Catalogs](./catalogs.md) — publish and consume shareable `.agents` payloads; standalone and colocated layouts.
|
|
26
|
+
- [Conventions](./conventions.md) — place a resource once, specialize downward, never copy.
|
|
27
|
+
- [Local dotagents development](./local-development.md) — a personal standalone `.agents` repo that trickles upstream.
|
|
28
|
+
- [Iterating on an agent](./iterating-on-profiles.md) — the edit-run-inspect loop.
|
|
29
|
+
- [Best practices](./best-practices.md) — few agents, many skills.
|
|
13
30
|
|
|
14
|
-
|
|
15
|
-
- [Agents](./agents.md) — The `agents/<id>/agent.md` resource and its loadout — what you run.
|
|
16
|
-
- [Agent profiles](./profiles.md) — Why an agent and its loadout _is_ the profile.
|
|
17
|
-
- [Personas](./personas.md) — The base-agent-plus-persona-documents review convention.
|
|
18
|
-
- [Subagents](./subagents.md) — Agents projected as harness delegates; leader-agent delegation.
|
|
19
|
-
- [Skills](./skills.md) — Capability packages with progressive disclosure, references, and routing.
|
|
20
|
-
- [Tasks](./tasks.md) — Placeholder for a separate upcoming RFC.
|
|
31
|
+
## Automate (surfaces)
|
|
21
32
|
|
|
22
|
-
|
|
33
|
+
The same composition runs on every surface; only the trigger changes.
|
|
23
34
|
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [Hooks](./hooks.md) —
|
|
35
|
+
- [Running an agent in GitHub Actions](./actions.md) — headless runs on any workflow trigger.
|
|
36
|
+
- [Recurring runs](./recurring-runs.md) — loops three ways: the local loop extension, Actions cron, cluster schedules.
|
|
37
|
+
- [In-cluster agents](./in-cluster.md) — resident agents, CronJobs, and subagent Jobs via Link Operator.
|
|
38
|
+
- [Hooks](./hooks.md) — harness hook wiring and the protocol gap.
|
|
39
|
+
- [Dump](./dump-and-bake.md) — deterministic, self-contained `.agents/` dumps.
|
|
28
40
|
- [State persistence](./state.md)
|
|
29
41
|
- [Adapter support matrix](./support-matrix.md)
|
|
30
42
|
|
|
31
|
-
##
|
|
43
|
+
## Use cases (stories)
|
|
32
44
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- [
|
|
36
|
-
- [
|
|
37
|
-
- [
|
|
38
|
-
- [
|
|
39
|
-
- [
|
|
45
|
+
Each use case is a worked story — a problem, the composition that answers it, and the payoff — with links back to the concepts it uses.
|
|
46
|
+
|
|
47
|
+
- [Shared conventions without duplication](./usecases/shared-conventions.md) — one conventional-commits rule for every user, org, and project; zero copies.
|
|
48
|
+
- [Flaky-test post-mortems in CI](./usecases/flaky-test-postmortems.md) — an on-failure step that classifies flake vs. regression and comments with evidence.
|
|
49
|
+
- [Grafana alert investigations in-cluster](./usecases/grafana-alert-investigator.md) — a webhook turns each firing alert into one bounded investigation Job.
|
|
50
|
+
- [Self-improving skills](./usecases/self-improving-skills.md) — a weekly loop that proposes skill edits and ships only measured improvements.
|
|
51
|
+
- [Resident agents: a researcher wiki](./usecases/resident-agents.md) — a long-lived agent that turns an email inbox into a compounding, reviewable knowledge base.
|
|
52
|
+
- [Persona reviews](./usecases/persona-reviews.md) — a base review agent plus customer-persona documents for feedback on ideas, docs, and designs.
|
|
53
|
+
- [Organization catalog](./usecases/organization-profile-catalog.md) — publish shared org resources and defaults through an `owner/.outfitter` control repository.
|
|
54
|
+
- [Engineering catalog](./usecases/engineering.md) — package engineering agents and skills for repeatable workflows.
|
|
40
55
|
|
|
41
|
-
##
|
|
56
|
+
## Reference
|
|
42
57
|
|
|
43
|
-
- [
|
|
44
|
-
- [
|
|
45
|
-
- [
|
|
58
|
+
- [CLI reference](./cli.md)
|
|
59
|
+
- [Migration from legacy profiles](./migration.md)
|
|
60
|
+
- [Philosophy](../philosophy.md) — why Outfitter exists.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Running an agent in GitHub Actions
|
|
2
2
|
|
|
3
|
-
[`ai-outfitter/actions`](https://github.com/ai-outfitter/actions)
|
|
3
|
+
[`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) is the GitHub Actions execution surface for Outfitter [agents](./agents.md). The planned interface asks Outfitter to resolve and compose the selected agent — the same loadout it would compose locally — then launches the harness in headless print mode, so the agent does one unit of work per workflow run and exits.
|
|
4
|
+
|
|
5
|
+
> **Status:** the `.agents`-native `ai-outfitter/actions@v2` interface described on this page is a design preview and is not published. The current `@v1` Action uses the removed profile-era `profile`, `prompt`, and `profile-source` inputs and must be pinned to a compatible pre-v1 Outfitter release. Do not copy the workflow below until `@v2` is released.
|
|
4
6
|
|
|
5
7
|
```yaml
|
|
6
8
|
# .github/workflows/issue-triage.yml
|
|
@@ -22,6 +22,7 @@ An agent is the protocol's identity resource — and, in Outfitter, the thing yo
|
|
|
22
22
|
```markdown
|
|
23
23
|
---
|
|
24
24
|
name: engineer
|
|
25
|
+
label: Engineer
|
|
25
26
|
description: Implements features and fixes with a bias toward small, verifiable changes.
|
|
26
27
|
skills: [wiki, research]
|
|
27
28
|
subagents: [code-reviewer]
|
|
@@ -39,6 +40,10 @@ tools:
|
|
|
39
40
|
You implement changes directly, keep diffs small, and verify before claiming done...
|
|
40
41
|
```
|
|
41
42
|
|
|
43
|
+
`name` is the stable slug used for resolution. The optional `label` is the human-readable profile
|
|
44
|
+
name shown during setup and in interactive harness UI. When `label` is omitted, Outfitter uses the
|
|
45
|
+
first level-one Markdown heading, then falls back to the slug.
|
|
46
|
+
|
|
42
47
|
Keep the prose focused on durable identity and behavior. Per-capability procedures belong in [skills](./skills.md); the frontmatter only _selects_ resources by slug — it never copies their content.
|
|
43
48
|
|
|
44
49
|
### Loadout fields
|
|
@@ -4,12 +4,12 @@ How an `outfitter` launch goes from configuration files to a running agent:
|
|
|
4
4
|
|
|
5
5
|
```mermaid
|
|
6
6
|
flowchart LR
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
settings[Settings] --> sources[Sources]
|
|
8
|
+
sources --> layers[".agents layers"]
|
|
9
|
+
layers --> resolver[Resolver]
|
|
10
|
+
resolver --> composed["Composed agent"]
|
|
11
|
+
composed --> adapter[Adapter]
|
|
12
|
+
adapter --> harness[Harness]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Settings tell Outfitter where `.agents` resources come from; sources supply protocol resource trees; the resolver merges the layered trees into one effective resource set; the selected agent composes its loadout — skills, subagents, model, and so on — from that set by slug; and an adapter projects the composed agent into harness-specific files, flags, and environment variables before launching the harness (pi or Claude Code).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Conventions
|
|
2
|
+
|
|
3
|
+
A resource that "belongs everywhere" is a _placement_ problem, not a duplication problem. This page names the convention that keeps a growing `.agents` ecosystem from collapsing into copies: **place a resource once, specialize downward, never copy.**
|
|
4
|
+
|
|
5
|
+
The mechanisms already exist — layer inheritance, merge-by-ID overrides, [loadout-added references](./skills.md#loadout-added-references), and progressive disclosure. The convention is agreeing to use them in order:
|
|
6
|
+
|
|
7
|
+
1. **Author once at the most general layer where the resource is true**, then let lower layers inherit it.
|
|
8
|
+
2. **Specialize downward** via same-ID overrides and loadout-added references, instead of forking or copying.
|
|
9
|
+
3. **Split by whether the agent should _decide_.** Ambient rules an agent should never think about belong in always-on shared context; situational capabilities belong in [skills](./skills.md), where progressive disclosure keeps them to roughly one line of context until they activate.
|
|
10
|
+
|
|
11
|
+
## Layer homes
|
|
12
|
+
|
|
13
|
+
Each layer inherits the one above it. ID-addressed resources — agents, skills, knowledge — merge and override by ID; root shared context (`agents.md` / `system-prompt.md`) is selected whole-file by layer precedence (see the [roadmap note](#roadmap-a-shareable-prompt-fragment) below):
|
|
14
|
+
|
|
15
|
+
| Layer | Location | Holds |
|
|
16
|
+
| ---------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
17
|
+
| Community | e.g. `ai-outfitter/community-profiles` | Reviewed building blocks — skills and reference agents anyone can mix and match. |
|
|
18
|
+
| Curated defaults | e.g. `ai-outfitter/default-profiles` | The pinned, curated assembly — starter agents users adopt as-is. |
|
|
19
|
+
| Organization | `owner/.outfitter` [control repo](./usecases/organization-profile-catalog.md) | Bespoke org agents, shared `agents.md`, org-specific skills (brand voice, RBAC, endpoints). |
|
|
20
|
+
| User / project | `~/.agents`, `<repo>/.agents` | Personal and repo overrides, loadout-added references, same-ID resource overrides. |
|
|
21
|
+
|
|
22
|
+
Generalized, these layers are **the ladder** — you prove an agent profile, skill, or loadout out in your own tree, then move it up a layer each time more people should get it, and every layer below inherits it back: community publishes the parts, curated catalogs pin an assembly, org and project bind values and override by ID.
|
|
23
|
+
|
|
24
|
+
## Where each kind of rule lives
|
|
25
|
+
|
|
26
|
+
| Rule type | Home | Agent decides? |
|
|
27
|
+
| ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------ |
|
|
28
|
+
| Ambient, always-true (conventional commits, secret hygiene, small reversible changes) | Shared context: the tree's `agents.md` / `system-prompt.md`, inherited per layer | Never |
|
|
29
|
+
| Situational capability or procedure (release notes, incident response, SEO audit) | A [skill](./skills.md) selected by slug (progressive disclosure) | Yes, on activation |
|
|
30
|
+
| Mechanically checkable (commit format, lint, formatting) | A [hook](./hooks.md) or CI check, plus the one-line ambient rule | Never |
|
|
31
|
+
|
|
32
|
+
The first row is the one teams get wrong most often: an ambient rule made into a skill forces every agent to _notice and choose_ it, and an ambient rule pasted into every `agent.md` becomes N drifting copies. Keep it in shared context, once, at the highest layer where it holds. When a selected skill already defines a capability, an agent definition MUST NOT copy or paraphrase it — the [skills doc](./skills.md#where-context-and-instructions-live) draws the same boundary.
|
|
33
|
+
|
|
34
|
+
## Worked example: conventional commits
|
|
35
|
+
|
|
36
|
+
Conventional commits "belongs in every profile" — the engineer, the marketing agent that occasionally commits copy, the CI bot — yet must never be pasted into every profile. It is the canonical ambient rule:
|
|
37
|
+
|
|
38
|
+
- **Author once** — one line in the shared `agents.md` of the highest layer where it holds (the org tree, or your `~/.agents/system-prompt.md` for everything on one machine).
|
|
39
|
+
- **Inherit downward** — every agent composed from that tree carries the rule with zero per-agent cost and no activation decision.
|
|
40
|
+
- **Override downward** — a project with a different commit convention ships its own shared context in `<repo>/.agents/`; workspace precedence wins. Today the root file wins _whole_, not line by line — fragment-level override is the [roadmap primitive](#roadmap-a-shareable-prompt-fragment) — so keep shared context lean enough that a deliberate replacement stays cheap and reviewable.
|
|
41
|
+
- **Enforce deterministically** — a `commit-msg` hook or release tooling is the backstop; the ambient line keeps the model writing them right the first time.
|
|
42
|
+
|
|
43
|
+
The full story, including projection into native harness files, is the [Shared conventions use case](./usecases/shared-conventions.md).
|
|
44
|
+
|
|
45
|
+
## Worked example: a role profile
|
|
46
|
+
|
|
47
|
+
The same convention builds a role-scoped profile — a `platform` or `marketing` agent ([#197](https://github.com/ai-outfitter/outfitter/issues/197)):
|
|
48
|
+
|
|
49
|
+
- **Inherit the shared baseline** (the tree's `agents.md`), then add role skills on top — `brand-voice`, `content-drafting`, `seo-audit` for marketing; provisioning and observability skills for platform. _Few agents, many skills_ ([Best practices](./best-practices.md)).
|
|
50
|
+
- **Bespoke per org two ways:** as a [subagent](./subagents.md) other agents delegate role work to, or via one org-specific skill (a `brand` or `platform` skill) carrying the values — endpoints, voice, RBAC — that make the shared profile bespoke without duplicating it.
|
|
51
|
+
- **Role separation is the point.** An engineer or a marketer doesn't want the other's machinery in context; they work in their own lane and delegate across lanes when needed. Cross-cutting work stays _available_ through inheritance and delegation, not by stuffing every profile.
|
|
52
|
+
|
|
53
|
+
## Roadmap: a shareable prompt fragment
|
|
54
|
+
|
|
55
|
+
Today the always-on vehicle is a tree's root `agents.md` / `system-prompt.md` — one file per layer. It inherits and overrides _per layer_, but you cannot yet publish one named fragment from a community catalog and override just that fragment by ID. A first-class, slug-composable shared prompt fragment is the missing primitive; until it lands, a single line per layer's shared context still deduplicates by inheritance — just not as a publishable unit. [Hooks](./hooks.md) carry the analogous gap for portable hook definitions.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# In-cluster agents
|
|
2
|
+
|
|
3
|
+
The Link Operator runs Outfitter-composed agents inside a Kubernetes cluster. The operator provides **primitives only** — namespace, quota, secret injection, pinned catalog resolution, and starting the runtime — while everything behavioral (which agent, which skills, which channels) stays ordinary `.agents` composition, reviewed and pinned like anywhere else.
|
|
4
|
+
|
|
5
|
+
> **Status:** the Link Operator is not yet publicly released. This page is the design contract for the in-cluster surface — treat it as a preview until the operator ships.
|
|
6
|
+
|
|
7
|
+
## The primitives
|
|
8
|
+
|
|
9
|
+
- **`Organization`** — ownership plus one commit-pinned catalog source. The operator writes the pin into the runtime's `.agents/settings.yml`; agents resolve their composition from it exactly as a local run would.
|
|
10
|
+
- **`Agent`** — a namespace of its own (`agent-<name>`), a service account bound only within that namespace, operator-owned quota and limits, a durable volume, and a long-running Deployment for the resident runtime.
|
|
11
|
+
|
|
12
|
+
The operator never interprets a profile, reads a secret's contents, or invokes the model — it provisions and starts; the agent layer does the rest.
|
|
13
|
+
|
|
14
|
+
## Execution shapes
|
|
15
|
+
|
|
16
|
+
| Shape | Kubernetes resource | Trigger |
|
|
17
|
+
| ---------------------- | ------------------- | ----------------------------------------------------------------------------------------------- |
|
|
18
|
+
| Resident agent | Deployment | The [loop extension](./recurring-runs.md) tick (default 10m): survey channels, work or delegate |
|
|
19
|
+
| Scheduled recurrence | CronJob | The cluster's clock — recurring one-shots in the agent's namespace |
|
|
20
|
+
| Delegated / event work | Job (subagent) | Spawned by the resident agent, or one Job per incoming event (e.g. a firing alert via webhook) |
|
|
21
|
+
|
|
22
|
+
Subagent Jobs share the owning agent's service account and quota, so delegation never escalates privilege — the cluster-backed entry in the [four delegation boundaries](./subagents.md#the-four-delegation-boundaries).
|
|
23
|
+
|
|
24
|
+
## Channels
|
|
25
|
+
|
|
26
|
+
A **channel** is an adapter to an external event or message source — email, GitHub notifications, Signal — that supplies the agent's work intake. Channels are agent-runtime concerns, composed as skills, MCP servers, or extensions in the catalog; they are never operator primitives. Two intake styles:
|
|
27
|
+
|
|
28
|
+
- **Poll** — the resident loop's tick surveys the channel (an inbox, a notifications feed) for new items.
|
|
29
|
+
- **Push** — a webhook receiver materializes one bounded subagent Job per event.
|
|
30
|
+
|
|
31
|
+
Treat channel content — email bodies, issue text, alert annotations — as untrusted data, never instructions, the same trust rule as [skill references](./skills.md#trust-boundary).
|
|
32
|
+
|
|
33
|
+
## Worked story
|
|
34
|
+
|
|
35
|
+
[Grafana alert investigations in-cluster](./usecases/grafana-alert-investigator.md): an Alertmanager webhook turns each firing alert into one investigation Job that reads dashboards and logs through the Grafana MCP plus a read-only Kubernetes view, classifies expected vs. anomaly, and posts exactly one diagnosis comment — never mutating a workload.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Recurring runs
|
|
2
|
+
|
|
3
|
+
Recurring agent work — "check this every N minutes", "review what landed overnight", "regenerate the weekly report" — runs three ways in the Outfitter ecosystem. All three run the **same composition** — the agent, its skills, its catalog pins — under the same contract: wake, survey your inputs, work, stop. What differs is the clock and the lifecycle: a loop extension re-invokes a live session on a tick (locally, and inside resident in-cluster agents), while the cron surfaces launch a fresh one-shot process per tick.
|
|
4
|
+
|
|
5
|
+
| Mechanism | Clock | Shape | Use when |
|
|
6
|
+
| ------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Local loop extension** | Your own session | The agent ticks inside a session on your machine (`/loop 10m`), surveying its inputs each tick | Watching something during your workday; developing a recurring behavior before automating it |
|
|
8
|
+
| **[GitHub Actions](./actions.md) cron** | The CI scheduler | `on: schedule:` workflow runs a fresh headless one-shot per tick | Repo-scoped recurrences: nightly commit review, weekly KPI reports, scheduled audits |
|
|
9
|
+
| **[In-cluster](./in-cluster.md) (Link Operator)** | Kubernetes | A scheduled recurring CronJob, or a resident Deployment that bootstraps the same `/loop` extension in-cluster | Always-on agents with channels (email, GitHub, chat) and cluster-local access; recurrences that shouldn't depend on a repo's CI |
|
|
10
|
+
|
|
11
|
+
The graduation path mirrors [the ladder](./conventions.md): prototype the behavior with the local loop extension, move it to an Actions cron when it should run without your laptop, move it in-cluster when it needs to be resident or cluster-local.
|
|
12
|
+
|
|
13
|
+
## Local: the loop extension
|
|
14
|
+
|
|
15
|
+
The loop extension re-invokes the agent at an interval inside a session. It is not bundled with a default install — select a loop extension in the agent's loadout (`extensions:`) and pin it like any other extension. Each tick, a well-shaped looping agent surveys its available inputs, turns new items into tasks, and works or delegates them — rather than carrying a growing transcript of stale context. The in-cluster resident agent runs the same way (see below).
|
|
16
|
+
|
|
17
|
+
## CI: scheduled one-shots
|
|
18
|
+
|
|
19
|
+
An Actions cron externalizes the clock to GitHub's scheduler. Each tick is a fresh, stateless headless run — compose, work once, exit — which makes it deterministic and reviewable, with a session transcript uploadable as a workflow artifact. See [`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) — its `examples/scheduled-commit-review.yml` reviews the last 24 hours of commits each weekday morning and files an issue on findings.
|
|
20
|
+
|
|
21
|
+
## Cluster: CronJobs and residents
|
|
22
|
+
|
|
23
|
+
Kubernetes contributes both a **scheduled** recurrence (a CronJob) and a **resident** one (a Deployment whose `/loop` tick surveys its [channels](./in-cluster.md#channels) for new work). The [in-cluster execution shapes](./in-cluster.md#execution-shapes) table is the reference for how the Link Operator provisions each.
|
|
24
|
+
|
|
25
|
+
## Not a loop: event-driven runs
|
|
26
|
+
|
|
27
|
+
A webhook- or event-triggered run — one investigation Job per firing alert, one post-mortem per failed workflow — is triggered by the world, not a clock. It complements loops rather than replacing them: use a loop when work accumulates and should be swept up on a tick; use an event trigger when each unit of work announces itself. See [Grafana alert investigations](./usecases/grafana-alert-investigator.md) and [Flaky-test post-mortems](./usecases/flaky-test-postmortems.md).
|
|
@@ -16,14 +16,25 @@ Each slug resolves to an `agents/<id>/` definition across layers like any other
|
|
|
16
16
|
|
|
17
17
|
See the [adapter support matrix](./support-matrix.md) for current coverage.
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## The four delegation boundaries
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Delegation is one concept — an agent hands a unit of work to another agent identity — with four boundaries it can cross. The composition being delegated to is ordinary `.agents` resources in every case; what changes is where the delegate runs and how it reports back.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
| Boundary | Mechanism | Reports back via | Use when |
|
|
24
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
|
|
25
|
+
| **In-run** | Harness-native subagents (Claude Code's agents directory, Pi's subagent extension), declared in the leader's `subagents` loadout | Inline, same session | Exploration, review, parallelizable work needing a fresh context now |
|
|
26
|
+
| **CI-backed** | A [GitHub Actions run](./actions.md): dispatch a workflow that does the work, or **assignment-as-trigger** — assign the issue/PR to a machine account whose events start the workflow (runs on hosted or self-hosted runners) | A comment or PR from the run; optionally a session-transcript artifact (adapter-dependent) | Work that should run asynchronously with its own token scope and an auditable trail |
|
|
27
|
+
| **Cluster-backed** | A Kubernetes subagent Job in the delegating agent's namespace, sharing its service account and quota ([in-cluster agents](./in-cluster.md)) | The tracking issue/PR, or the delegating agent's next tick | Cluster-local work; one bounded Job per delegated unit or per incoming event |
|
|
28
|
+
| **Peer agent** | Notify or assign a _persistent_ resident agent — its notifications channel is the intake | Wherever the peer works: the issue, the PR, the thread | Standing responsibilities owned by an always-on identity rather than one-off runs |
|
|
25
29
|
|
|
26
|
-
A leader's loadout
|
|
30
|
+
A leader's loadout declares in-run delegates as `subagents`; the other three boundaries are reached through the tools the leader already has (dispatching a workflow, assigning an issue, filing work where a peer listens). Keep each delegate bounded — one job, clear inputs, a defined deliverable back to the caller.
|
|
31
|
+
|
|
32
|
+
## Delegation patterns
|
|
33
|
+
|
|
34
|
+
Two patterns recur on top of the boundaries:
|
|
35
|
+
|
|
36
|
+
- **Adversarial review.** Delegate critique to a _differently composed_ identity than the author — a different model, persona, or loadout, often a machine account, so the review carries no author bias and a visibly separate identity. The [personas convention](./personas.md) supplies the reviewer shape; the CI-backed boundary supplies the separate identity and audit trail.
|
|
37
|
+
- **Singleton coordinator.** Invert the fan-out: you always talk to **one** persistent agent (a machine account listening to its GitHub notifications), which keeps a bounded, prioritized queue and always chooses what to work on next. Everything else — CI runs, cluster Jobs, in-run subagents — is _its_ delegation target. The human interface stays one conversation; concurrency lives below it. "Assign the PR to the agent" becomes the entire UX.
|
|
27
38
|
|
|
28
39
|
## When to give an agent subagents
|
|
29
40
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Flaky-test post-mortems in CI
|
|
2
|
+
|
|
3
|
+
Slow system tests tax a team twice: once waiting for the run, and again when a red X lands and someone has to decide whether it is a real regression or last week's timing flake. Most of that second tax is mechanical — fetch the logs, compare against the diff, remember whether this failure signature has appeared before — which makes it delegable.
|
|
4
|
+
|
|
5
|
+
## The composition
|
|
6
|
+
|
|
7
|
+
One optional on-failure step hands the event to the shared CI agent the repository already runs through [`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) — no new workflow, no new agent:
|
|
8
|
+
|
|
9
|
+
- **Trigger.** The test workflow's failure (`if: failure()`) invokes the shared agent with structured `trigger_context` — workflow name, run id, a `failure_kind` — as opaque routing metadata, never as instructions ([Running an agent in GitHub Actions](../actions.md)).
|
|
10
|
+
- **Routing.** The agent maps `failure_kind: system-tests` to exactly one skill, a `test-postmortem` capability; the skill then fetches logs and the diff with trusted tools. This is the _few agents, many skills_ shape from [Best practices](../best-practices.md) — adding release-note triage later adds a skill and an activation rule, not another agent.
|
|
11
|
+
- **Verdict.** The skill classifies flake vs. real regression with a confidence level and posts one comment on the PR with its evidence. Comment-only is the safe default mode.
|
|
12
|
+
- **Audit.** The run uploads its session transcript as a workflow artifact, so anyone can read exactly how the agent reached its verdict.
|
|
13
|
+
|
|
14
|
+
## Escalation, governed
|
|
15
|
+
|
|
16
|
+
Auto-fixing is opt-in and label-gated: with the label present, the agent may push a single fix commit under a machine-account token (the default `GITHUB_TOKEN` deliberately cannot re-trigger CI). Stacked guards keep the loop bounded — a recursion guard, an attempt cap that hands off to a human, workflow `concurrency` with `cancel-in-progress` and `timeout-minutes`, and the label itself limiting blast radius. The machine-account and token-scoping decisions are documented in the [`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) credential guides.
|
|
17
|
+
|
|
18
|
+
## Payoff
|
|
19
|
+
|
|
20
|
+
The red X arrives already triaged: a verdict, a confidence, the evidence, and a transcript — and the team decides only what to do about it. The delegation crosses the [CI-backed boundary](../subagents.md#the-four-delegation-boundaries); the same event-driven shape powers [alert investigations in-cluster](./grafana-alert-investigator.md).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Grafana alert investigations in-cluster
|
|
2
|
+
|
|
3
|
+
Resource alerts are noisy: CPU pinned where it is always pinned, a pod that quietly died and restarted, an OOMKill that actually matters. A human triages every one, or the channel gets muted. The triage itself — scope to the resource, read the dashboards and logs for the alert window, decide expected vs. anomaly — is bounded work an agent can do per alert.
|
|
4
|
+
|
|
5
|
+
## The composition
|
|
6
|
+
|
|
7
|
+
- **Trigger.** A `kube-prometheus-stack` Alertmanager webhook receiver (added with `continue: true`, so human paging is untouched) turns each firing alert into one bounded headless run; alert labels travel as untrusted channel data used only for routing, never as instructions ([trust boundary](../skills.md#trust-boundary)).
|
|
8
|
+
- **Agent.** The community-catalog `grafana-agent` profile ([community-profiles#10](https://github.com/ai-outfitter/community-profiles/pull/10)) routes alert work to two agent-local skills — investigate and issue-triage — plus a per-agent MCP declaration for the already-running [`grafana/mcp-grafana`](https://github.com/grafana/mcp-grafana) server, giving it Loki, Prometheus, Tempo, and Pyroscope, alongside a read-only Kubernetes view. The same profile owns the setup half (provisioning that MCP securely) behind a separate, explicitly-requested-only skill.
|
|
9
|
+
- **Verdict.** The investigation is scoped to the alerting resource and the alert window, and classifies the alert `expected` (known-noisy — recommend tuning or ignoring the rule) or `anomaly` (OOMKill, non-zero exit, a new hot path) with a confidence level.
|
|
10
|
+
- **Safe default.** The agent posts exactly one diagnosis comment on the existing tracking issue. It never mutates a workload and never edits the issue — comment-only is the only mode.
|
|
11
|
+
|
|
12
|
+
## The wiring
|
|
13
|
+
|
|
14
|
+
The agent itself is deliberately deployment-agnostic; the Link Operator's webhook-driven design supplies the in-cluster wiring ([In-cluster agents](../in-cluster.md) — a design preview until the operator ships): a webhook receiver channel materializes **one subagent Job per firing alert** in the agent's namespace, sharing its service account and quota — bounded, timeout-enforced, read-only RBAC. This is the push style of channel intake; the same agent could instead be swept up by a resident agent's [loop tick](../recurring-runs.md).
|
|
15
|
+
|
|
16
|
+
## Payoff
|
|
17
|
+
|
|
18
|
+
Every alert arrives with a diagnosis already attached: what fired, what the dashboards and logs show for the window, expected or anomaly, and with what confidence — and the on-call human spends attention only on the anomalies. Setting up the observability stack this rides on (provisioning Grafana alerting, the MCP server, read-only RBAC) is platform-profile work — the [role-profile convention](../conventions.md#worked-example-a-role-profile) ([#197](https://github.com/ai-outfitter/outfitter/issues/197)).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Resident agents: a researcher wiki
|
|
2
|
+
|
|
3
|
+
Knowledge work accumulates faster than anyone organizes it: the paper a colleague forwarded, the article dying in a browser tab, the half-formed connection between them that lives nowhere at all. The standard machine answer — embed everything and retrieve over it — re-derives understanding from scratch on every question and throws the derivation away with the answer; ask twice and the system does the same work twice, no smarter the second time.
|
|
4
|
+
|
|
5
|
+
The alternative is an agent that organizes material _as it arrives_: a long-lived resident that maintains a persistent, compounding markdown wiki. The pattern is Andrej Karpathy's ["LLM Wiki" gist](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) — an LLM curating an interlinked knowledge base as its durable memory — worked here as an Outfitter composition.
|
|
6
|
+
|
|
7
|
+
## The composition
|
|
8
|
+
|
|
9
|
+
- **Resident, not invoked.** The maintainer is a long-lived in-cluster agent — a resident Deployment from [In-cluster agents](../in-cluster.md) — whose [loop tick](../recurring-runs.md) surveys its channels for new work. An email inbox is the intake: email a paper, an article, or a stray thought to the agent's address, and the next tick picks it up.
|
|
10
|
+
- **Ingest per message.** Each new source becomes one bounded ingest:
|
|
11
|
+
- a summary page written in the wiki's own voice and link style;
|
|
12
|
+
- the entity and concept pages the source touches cross-referenced and updated;
|
|
13
|
+
- contradictions with older claims flagged on the page, never silently overwritten;
|
|
14
|
+
- the index and an append-only ingest log updated, so the wiki's growth is itself readable history;
|
|
15
|
+
- a reply sent in-thread pointing at the wiki commit that resulted.
|
|
16
|
+
|
|
17
|
+
Email bodies and attachments are **untrusted data, never instructions** — the same trust rule every [channel](../in-cluster.md#channels) carries.
|
|
18
|
+
|
|
19
|
+
- **The wiki is the durable state.** The wiki is a git repository of markdown. The agent's runs stay stateless and restart-safe because the system of record lives outside the process — and every change the agent makes is a commit a human can review, diff, or revert. There is no opaque memory to trust; the agent's understanding _is_ the repository.
|
|
20
|
+
- **Query and lint ride the same composition.** Ask a question by mail or issue and the answer cites wiki pages, with any durable synthesis filed back as pages of its own — so explorations compound instead of evaporating. A scheduled lint pass — a cluster CronJob, or an Actions cron if the wiki repo's CI should own it ([Recurring runs](../recurring-runs.md)) — opens a PR listing contradictions, orphaned pages, stale claims, and suggested sources worth ingesting next.
|
|
21
|
+
|
|
22
|
+
## The wiring
|
|
23
|
+
|
|
24
|
+
The agent itself is deployment-agnostic; the resident shape comes from the in-cluster design ([In-cluster agents](../in-cluster.md) — a design preview until the operator ships). An `Agent` resource gives the maintainer its own namespace, service account, and durable volume; the resident Deployment bootstraps the same `/loop` extension you would run locally, on a default 10-minute tick; and a heavyweight ingest can be delegated to a subagent Job that shares the agent's service account and quota. The inbox is the poll style of channel intake — the complement of the push style that powers [alert investigations](./grafana-alert-investigator.md).
|
|
25
|
+
|
|
26
|
+
## Payoff
|
|
27
|
+
|
|
28
|
+
The wiki compounds instead of being re-derived. A question asked in month six is answered against six months of cross-linked, human-reviewable understanding rather than a fresh retrieval pass over raw sources, and the knowledge base's maintenance arrives as reviewable PRs, not silent drift. The lint report doubles as a free scoring signal: its findings can gate skill edits much as the CAD benchmark does in [Self-improving skills](./self-improving-skills.md).
|
|
29
|
+
|
|
30
|
+
## Graduation
|
|
31
|
+
|
|
32
|
+
The profile packaging this — a `wiki-maintainer` agent with agent-local ingest, query, and lint skills, in review in [`ai-outfitter/community-profiles`](https://github.com/ai-outfitter/community-profiles) — climbs the usual ladder:
|
|
33
|
+
|
|
34
|
+
1. **Personal** — the same agent at your desk with the local loop extension, pointed at a personal wiki repo.
|
|
35
|
+
2. **Org** — intake moves to an Actions cron over a shared knowledge-base repo when it should run without your laptop.
|
|
36
|
+
3. **Communal** — resident in-cluster, where every contributor's agent runs the same pinned profile against the same wiki.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Self-improving skills
|
|
2
|
+
|
|
3
|
+
A skill is a markdown file — which means it can be _trained_. [`ai-outfitter/autoimprove`](https://github.com/ai-outfitter/autoimprove) treats a skill as the trainable parameter of a frozen agent: replay real tasks against the current skill text, propose small edits, and accept only the edits that measurably improve a held-out score.
|
|
4
|
+
|
|
5
|
+
## The loop
|
|
6
|
+
|
|
7
|
+
1. **Rollout** — run the agent with the current skill over a batch of tasks, scoring each result.
|
|
8
|
+
2. **Reflect** — an optimizer model reads the failures and proposes bounded `add`/`delete`/`replace` edits, capped per step (a textual learning rate).
|
|
9
|
+
3. **Gate** — candidate skills are evaluated on a held-out validation split; an edit is accepted only on _strict_ improvement, and a never-touched test split keeps the final numbers honest.
|
|
10
|
+
|
|
11
|
+
The worked example is a parametric CAD skill ([autoimprove#2](https://github.com/ai-outfitter/autoimprove/pull/2)): a `generate-replicad-cad` skill scored by executable CAD and assembly checks — the failures that matter (fused parts, broken clearances) are exactly the ones executable evaluation catches, and deterministic non-regression gates keep a clever edit from breaking working cases.
|
|
12
|
+
|
|
13
|
+
## Scheduling and review
|
|
14
|
+
|
|
15
|
+
The training loop is itself a [recurring run](../recurring-runs.md): a weekly GitHub Actions cron replays the benchmark, and when the gate accepts an improvement, the automation refreshes a single draft PR with the new skill text and its before/after scores. **The skill never self-merges** — a human reviews a readable diff of the skill's actual instructions, with the measurement attached. The blast radius of "the agent got smarter" is a pull request.
|
|
16
|
+
|
|
17
|
+
## Graduation
|
|
18
|
+
|
|
19
|
+
A skill that keeps passing its gate is a candidate for [the ladder](../conventions.md): promote the pinned, validated revision from the personal or project tree into a shared catalog, and every engineer's agent can select it by slug — without owning the trainer, the benchmark, or the credentials that produced it. Training infrastructure stays where it ran; only the proven capability graduates.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Shared conventions without duplication
|
|
2
|
+
|
|
3
|
+
Every agent that touches a repository should write [Conventional Commits](https://www.conventionalcommits.org/): the engineer agent, the marketing agent that occasionally commits copy, the CI bot that opens automated PRs. The rule is universal — and that is exactly what makes it dangerous to manage naively.
|
|
4
|
+
|
|
5
|
+
## The failure mode
|
|
6
|
+
|
|
7
|
+
The naive path pastes the rule into every `agent.md`, every project's `CLAUDE.md`, every teammate's personal prompt. Now there are N copies: they drift as people tweak wording, every copy occupies every context window on every run, and a new agent starts without the rule until someone remembers. Making it a skill is the subtler mistake — a skill implies an _activation decision_, and no agent should ever spend a thought deciding whether commit formatting applies. It should simply always be true.
|
|
8
|
+
|
|
9
|
+
## The composition
|
|
10
|
+
|
|
11
|
+
Author the rule **once, at the most general layer where it holds**, and let every layer below inherit it:
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
<!-- org catalog: .agents/agents.md -->
|
|
15
|
+
|
|
16
|
+
Use Conventional Commits for every commit message, with scopes
|
|
17
|
+
(for example `fix(setup): ...`, `docs(runtime): ...`).
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- **Every user, every project, every agent** composed from the org catalog now carries the rule — one authored copy, zero activation cost, no per-agent duplication.
|
|
21
|
+
- **A single user** who wants it everywhere on one machine before the org adopts it drops the same line in `~/.agents/system-prompt.md` — the quickest way to give everything you run a shared rule.
|
|
22
|
+
- **A project that differs** (say, a repo that squash-merges with its own title format) ships its own shared context in `<repo>/.agents/` — workspace precedence wins for that repo only. Note the granularity: today the root shared-context file wins _whole_, not line by line (fragment-level override is the [roadmap primitive](../conventions.md#roadmap-a-shareable-prompt-fragment)), so the project file deliberately carries the shared context it still wants — a reviewable replacement in the repo it affects.
|
|
23
|
+
- **Enforcement stays deterministic** — a `commit-msg` [hook](../hooks.md) or release tooling backstops the rule mechanically; the ambient line keeps the model writing it right the first time.
|
|
24
|
+
|
|
25
|
+
The same placement works for every ambient rule: secret hygiene, small reversible changes, "write decisions into repository files." The test is the [conventions](../conventions.md) split — if the agent should never _decide_ about it, it belongs in shared context, not in a skill.
|
|
26
|
+
|
|
27
|
+
## A second fragment: repository layout
|
|
28
|
+
|
|
29
|
+
A second convention of the same shape — illustrative here, and the kind of rule a default catalog adopts as `project-repos` — standardizes where code lives on a machine:
|
|
30
|
+
|
|
31
|
+
```markdown
|
|
32
|
+
<!-- default catalog shared context -->
|
|
33
|
+
|
|
34
|
+
Repositories are checked out at `~/repos/<org-or-username>/<repo>/`;
|
|
35
|
+
linked worktrees live beside them at
|
|
36
|
+
`~/repos/<org-or-username>/<repo>.worktrees/`.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The value is ambiguity reduction: every agent — and every skill that clones, opens a worktree, or navigates between projects — knows where a repository lives without asking or guessing, and automation composed from the catalog can rely on the same paths on every machine. A user who keeps a different layout supplies their own amended shared context in `~/.agents` (again, a whole-file replacement today) and keeps using the shared profiles unchanged — or builds their own profiles from scratch. Either way the catalog never forks over a filesystem preference.
|
|
40
|
+
|
|
41
|
+
## Reaching native harness runs
|
|
42
|
+
|
|
43
|
+
Composition only helps runs that go through it — the rule should also reach a bare `claude` session that never touches Outfitter. The porting design ([Porting a Claude Code setup](../porting-claude.md)) maps `~/.claude/CLAUDE.md` to `~/.agents/agents.md` with a symlink back, so native Claude Code reads the protocol tree and editing either view edits the same file; managed porting and persistent harness symlinks — including the generalization of projecting composed shared context into each harness's home-level memory file — are deferred to [#187](https://github.com/ai-outfitter/outfitter/issues/187).
|
|
44
|
+
|
|
45
|
+
## Payoff
|
|
46
|
+
|
|
47
|
+
One rule, authored once, inherited by every user, org, and project layer; overridable exactly where it should differ; enforced mechanically; visible in native harnesses. The context cost across the whole fleet is a single line — and when the org rewords the rule, one PR to one file updates every agent's next run.
|
package/package.json
CHANGED