@ai-outfitter/outfitter 1.0.2 → 1.1.0

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.
Files changed (74) hide show
  1. package/README.md +33 -23
  2. package/code/enterprise/cli/privateCatalogGate.cjs +3 -3
  3. package/code/pi-extension/src/outfitter-runtime-extension.js +45 -6
  4. package/dist/cli/OutfitterCli.js +4 -7
  5. package/dist/cli/OutfitterCli.js.map +1 -1
  6. package/dist/cli/commands/DumpCommand.js +8 -3
  7. package/dist/cli/commands/DumpCommand.js.map +1 -1
  8. package/dist/cli/commands/ListCommand.js +4 -3
  9. package/dist/cli/commands/ListCommand.js.map +1 -1
  10. package/dist/cli/commands/PiRuntimeLaunch.d.ts +14 -4
  11. package/dist/cli/commands/PiRuntimeLaunch.js +23 -27
  12. package/dist/cli/commands/PiRuntimeLaunch.js.map +1 -1
  13. package/dist/cli/commands/RunAgentCommand.js +8 -3
  14. package/dist/cli/commands/RunAgentCommand.js.map +1 -1
  15. package/dist/cli/commands/SetupCommand.d.ts +1 -1
  16. package/dist/cli/commands/SetupCommand.js +6 -13
  17. package/dist/cli/commands/SetupCommand.js.map +1 -1
  18. package/dist/cli/commands/SyncCommand.d.ts +31 -0
  19. package/dist/cli/commands/SyncCommand.js +162 -0
  20. package/dist/cli/commands/SyncCommand.js.map +1 -0
  21. package/dist/cli/commands/ValidateCommand.js +4 -2
  22. package/dist/cli/commands/ValidateCommand.js.map +1 -1
  23. package/dist/composer/Composer.js +1 -0
  24. package/dist/composer/Composer.js.map +1 -1
  25. package/dist/composer/Composition.d.ts +2 -0
  26. package/dist/paths/RepositoryAssets.d.ts +4 -0
  27. package/dist/paths/RepositoryAssets.js +26 -0
  28. package/dist/paths/RepositoryAssets.js.map +1 -0
  29. package/dist/resolver/AgentDefinition.d.ts +2 -0
  30. package/dist/resolver/AgentDefinition.js +2 -0
  31. package/dist/resolver/AgentDefinition.js.map +1 -1
  32. package/dist/resolver/Layer.d.ts +17 -1
  33. package/dist/resolver/Layer.js +23 -15
  34. package/dist/resolver/Layer.js.map +1 -1
  35. package/dist/resolver/ResolverContext.d.ts +2 -0
  36. package/dist/resolver/ResolverContext.js +7 -2
  37. package/dist/resolver/ResolverContext.js.map +1 -1
  38. package/dist/schemas/agent.schema.json +1 -0
  39. package/dist/settings/SettingsLoader.d.ts +12 -3
  40. package/dist/settings/SettingsLoader.js +25 -11
  41. package/dist/settings/SettingsLoader.js.map +1 -1
  42. package/dist/setup/DefaultCatalog.d.ts +2 -1
  43. package/dist/setup/DefaultCatalog.js +25 -50
  44. package/dist/setup/DefaultCatalog.js.map +1 -1
  45. package/dist/sources/GitRepository.d.ts +28 -0
  46. package/dist/sources/GitRepository.js +139 -0
  47. package/dist/sources/GitRepository.js.map +1 -0
  48. package/dist/sources/PrivateCatalogGate.d.ts +27 -0
  49. package/dist/sources/PrivateCatalogGate.js +23 -0
  50. package/dist/sources/PrivateCatalogGate.js.map +1 -0
  51. package/dist/sources/SourceCache.d.ts +11 -1
  52. package/dist/sources/SourceCache.js +11 -2
  53. package/dist/sources/SourceCache.js.map +1 -1
  54. package/dist/version/OutfitterVersion.d.ts +1 -0
  55. package/dist/version/OutfitterVersion.js +8 -0
  56. package/dist/version/OutfitterVersion.js.map +1 -0
  57. package/docs/documentation/README.md +46 -31
  58. package/docs/documentation/actions.md +3 -1
  59. package/docs/documentation/agents.md +5 -0
  60. package/docs/documentation/catalogs.md +10 -2
  61. package/docs/documentation/cli.md +11 -3
  62. package/docs/documentation/concepts.md +6 -6
  63. package/docs/documentation/conventions.md +55 -0
  64. package/docs/documentation/in-cluster.md +35 -0
  65. package/docs/documentation/recurring-runs.md +27 -0
  66. package/docs/documentation/settings.md +4 -2
  67. package/docs/documentation/subagents.md +16 -5
  68. package/docs/documentation/usecases/flaky-test-postmortems.md +20 -0
  69. package/docs/documentation/usecases/grafana-alert-investigator.md +18 -0
  70. package/docs/documentation/usecases/resident-agents.md +36 -0
  71. package/docs/documentation/usecases/self-improving-skills.md +19 -0
  72. package/docs/documentation/usecases/shared-conventions.md +47 -0
  73. package/package.json +1 -1
  74. package/src/schemas/agent.schema.json +1 -0
@@ -1,6 +1,8 @@
1
1
  # Running an agent in GitHub Actions
2
2
 
3
- [`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) runs an Outfitter [agent](./agents.md) non-interactively inside a GitHub Actions workflow. The Action 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. Wire it to any trigger and an agent becomes a CI worker: a PR reviewer, a scheduled commit auditor, an issue triager.
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
@@ -101,11 +101,19 @@ Remote settings are cached locally and merged at lower precedence than your proj
101
101
 
102
102
  `outfitter sync` synchronizes every remote source into the local cache:
103
103
 
104
- 1. Remote settings repositories are cloned or updated first, then reloaded.
104
+ 1. Local settings are validated. Remote settings repositories are cloned or updated first, then
105
+ merged settings are reloaded.
105
106
  2. Remote sources (including any added by remote settings) are cloned or updated.
106
107
  3. Each synced source is validated; sync reports `updated`, `unchanged`, `skipped`, or `failed` per source.
107
108
 
108
- Pinned (`ref:`) sources stay on their pinned ref until you change it; unpinned sources fast-forward on every sync.
109
+ All repositories live under `<cache_directory>/repos/<encoded-uri-and-ref>/` (default
110
+ `~/.agents/cache`). Pinned (`ref:`) sources stay on their selected ref until you change it; unpinned
111
+ sources resolve the remote's current default branch on every sync.
112
+
113
+ Fetch and validation happen in a temporary sibling directory. Outfitter swaps a valid checkout into
114
+ place atomically, so a failed fetch or invalid update preserves the last working cache. A required
115
+ source failure makes sync exit nonzero. `outfitter run` remains offline with respect to source
116
+ synchronization; run sync explicitly when you want network updates.
109
117
 
110
118
  ## Private repositories
111
119
 
@@ -1,7 +1,5 @@
1
1
  # CLI reference
2
2
 
3
- > **Status: RFC [#165](https://github.com/ai-outfitter/outfitter/issues/165) target.** This reference describes the dotagents end-state command surface. The currently released CLI still implements the legacy profile commands; implementation PRs replace them incrementally.
4
-
5
3
  Global options:
6
4
 
7
5
  | Option | Description |
@@ -41,7 +39,17 @@ fallback.
41
39
 
42
40
  ## `outfitter sync`
43
41
 
44
- Synchronize remote sources and remote settings into the local cache. Reports a per-source status of `updated`, `unchanged`, `skipped`, or `failed`, and validates synced sources.
42
+ Synchronize remote sources and remote settings into the local cache. Sync validates local settings,
43
+ updates `remote_settings`, reloads the merged settings, and then updates the remote `sources` that
44
+ result. Each repository reports `updated`, `unchanged`, `skipped`, or `failed`.
45
+
46
+ Fetched content is validated in a temporary checkout before an atomic cache swap, so a failed fetch
47
+ or invalid update leaves the last valid cache available. Required-source failures and invalid
48
+ settings exit nonzero. Credentials embedded in URIs are redacted from status, errors, cache paths,
49
+ and Git output.
50
+
51
+ Sync is explicit: `outfitter run` never initiates network access. If a configured cache is absent,
52
+ resolution tells you to run `outfitter sync`.
45
53
 
46
54
  ## `outfitter list [kind]`
47
55
 
@@ -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
- A[Settings] --> B[Sources]
8
- B --> C[.agents layers]
9
- C --> D[Resolver]
10
- D --> E[Composed agent]
11
- E --> F[Adapter]
12
- F --> G[Harness]
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).
@@ -39,13 +39,15 @@ remote_settings:
39
39
  path: .agents/settings.yml
40
40
  ref: 9c47d1e2b8a05f36c4d7e90a12b3f8c5d6e71a04
41
41
 
42
- cache_directory: ~/.agents/cache
42
+ cache_directory: ./cache # optional; relative to this settings file
43
43
  ```
44
44
 
45
45
  - `default_agent` / `default_harness` — which agent plain `outfitter` runs, and the harness it launches in.
46
46
  - `sources` — ordered list of remote or local `.agents` payloads. Remote entries (`github:` / `uri:`) accept `ref:` pinning and an optional `path:` to the payload inside the repository; see [Catalogs](./catalogs.md) for conventions and trust guidance.
47
47
  - `remote_settings` — shared settings a repository distributes; cached locally and merged below your project and user settings, so anything you set locally wins.
48
- - `cache_directory` — where remote sources are cached (`outfitter sync` updates them).
48
+ - `cache_directory` — the repository cache root used consistently by sync, remote settings, remote
49
+ source resolution, and default-catalog setup. It defaults to `~/.agents/cache`; repositories live
50
+ below its `repos/` directory.
49
51
 
50
52
  ## Precedence
51
53
 
@@ -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
- ## Leader agents and delegation targets
19
+ ## The four delegation boundaries
20
20
 
21
- The reason to give an agent subagents is to make it a **leader**: an agent that coordinates work and delegates the bounded pieces. A leader can delegate two ways, and the two compose:
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
- - **To local coding-harness subagents** agents projected into the running harness (Claude Code's agents directory, Pi's subagent extension). The leader hands off exploration, review, or parallelizable work to a fresh context on the same machine and gets the result back inline.
24
- - **To issue- and action-backed subagents** work dispatched asynchronously, backed by a GitHub issue and an [Outfitter action](./actions.md). The leader files the unit of work as an issue; an action runs the delegate agent headlessly and reports back on the issue or PR. This is how a leader parallelizes across machines and across time rather than within one session.
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 is where both are declared: local delegates as `subagents`, remote work routed through the action it triggers. Keep each delegate bounded — one job, clear inputs, a defined deliverable back to the caller.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-outfitter/outfitter",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Profile-oriented wrapper for launching pi, Claude Code, and future agent CLIs with reproducible configuration.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -6,6 +6,7 @@
6
6
  "required": ["name"],
7
7
  "properties": {
8
8
  "name": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 64 },
9
+ "label": { "type": "string", "minLength": 1 },
9
10
  "description": { "type": "string" },
10
11
  "skills": {
11
12
  "$ref": "#/$defs/slugList",