@ai-outfitter/outfitter 0.9.0 → 0.11.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 (77) hide show
  1. package/.outfitter/skills/outfitter/SKILL.md +86 -0
  2. package/README.md +2 -0
  3. package/code/pi-extension/src/outfitter-extension.js +48 -19
  4. package/dist/agents/AdapterProfileControls.js +2 -2
  5. package/dist/agents/AdapterProfileControls.js.map +1 -1
  6. package/dist/agents/AgentAdapter.d.ts +0 -2
  7. package/dist/agents/LaunchResources.d.ts +4 -0
  8. package/dist/agents/LaunchResources.js +27 -1
  9. package/dist/agents/LaunchResources.js.map +1 -1
  10. package/dist/agents/OutfitterSkill.d.ts +11 -0
  11. package/dist/agents/OutfitterSkill.js +128 -0
  12. package/dist/agents/OutfitterSkill.js.map +1 -0
  13. package/dist/agents/claude/ClaudeAdapter.js +16 -1
  14. package/dist/agents/claude/ClaudeAdapter.js.map +1 -1
  15. package/dist/agents/pi/PiAdapter.js +4 -12
  16. package/dist/agents/pi/PiAdapter.js.map +1 -1
  17. package/dist/agents/pi/PiArgs.js +1 -1
  18. package/dist/agents/pi/PiArgs.js.map +1 -1
  19. package/dist/agents/pi/PiSkillSources.js +5 -1
  20. package/dist/agents/pi/PiSkillSources.js.map +1 -1
  21. package/dist/cli/OutfitterCli.js +0 -2
  22. package/dist/cli/OutfitterCli.js.map +1 -1
  23. package/dist/cli/commands/PiLoginLaunch.d.ts +5 -0
  24. package/dist/cli/commands/PiLoginLaunch.js +2 -0
  25. package/dist/cli/commands/PiLoginLaunch.js.map +1 -1
  26. package/dist/cli/commands/RunCommand.d.ts +0 -2
  27. package/dist/cli/commands/RunCommand.js +29 -9
  28. package/dist/cli/commands/RunCommand.js.map +1 -1
  29. package/dist/cli/commands/profile/LintCommand.js +33 -1
  30. package/dist/cli/commands/profile/LintCommand.js.map +1 -1
  31. package/dist/cli/commands/run/RunProfileResolution.d.ts +2 -0
  32. package/dist/cli/commands/run/RunProfileResolution.js +4 -0
  33. package/dist/cli/commands/run/RunProfileResolution.js.map +1 -1
  34. package/dist/profiles/Profile.d.ts +14 -1
  35. package/dist/profiles/Profile.js.map +1 -1
  36. package/dist/profiles/ProfileLoader.js +18 -2
  37. package/dist/profiles/ProfileLoader.js.map +1 -1
  38. package/dist/profiles/ProfileMerger.js +3 -2
  39. package/dist/profiles/ProfileMerger.js.map +1 -1
  40. package/dist/schemas/profile.schema.json +40 -3
  41. package/dist/skills/ProfileSkillResolution.d.ts +21 -0
  42. package/dist/skills/ProfileSkillResolution.js +88 -0
  43. package/dist/skills/ProfileSkillResolution.js.map +1 -0
  44. package/dist/skills/SkillCatalog.d.ts +41 -0
  45. package/dist/skills/SkillCatalog.js +119 -0
  46. package/dist/skills/SkillCatalog.js.map +1 -0
  47. package/dist/skills/SkillDocument.d.ts +21 -0
  48. package/dist/skills/SkillDocument.js +85 -0
  49. package/dist/skills/SkillDocument.js.map +1 -0
  50. package/dist/skills/SkillResolution.d.ts +34 -0
  51. package/dist/skills/SkillResolution.js +369 -0
  52. package/dist/skills/SkillResolution.js.map +1 -0
  53. package/{doc → docs}/documentation/README.md +4 -1
  54. package/docs/documentation/actions.md +97 -0
  55. package/docs/documentation/best-practices.md +105 -0
  56. package/{doc → docs}/documentation/profile-repository.md +74 -6
  57. package/docs/documentation/skills.md +485 -0
  58. package/{doc → docs}/documentation/support-matrix.md +4 -1
  59. package/package.json +4 -8
  60. package/src/schemas/profile.schema.json +40 -3
  61. package/dist/agents/OutfitterDocs.d.ts +0 -2
  62. package/dist/agents/OutfitterDocs.js +0 -38
  63. package/dist/agents/OutfitterDocs.js.map +0 -1
  64. package/skills/outfitter/SKILL.md +0 -68
  65. /package/{doc → docs}/architecture/state_writeback_strategy.md +0 -0
  66. /package/{doc → docs}/documentation/cli.md +0 -0
  67. /package/{doc → docs}/documentation/concepts.md +0 -0
  68. /package/{doc → docs}/documentation/first-time-cli-agent-users.md +0 -0
  69. /package/{doc → docs}/documentation/getting-started.md +0 -0
  70. /package/{doc → docs}/documentation/iterating-on-profiles.md +0 -0
  71. /package/{doc → docs}/documentation/profiles.md +0 -0
  72. /package/{doc → docs}/documentation/state.md +0 -0
  73. /package/{doc → docs}/documentation/switching-to-outfitter.md +0 -0
  74. /package/{doc → docs}/documentation/usecases/engineering.md +0 -0
  75. /package/{doc → docs}/documentation/usecases/organization-profile-catalog.md +0 -0
  76. /package/{doc → docs}/documentation/usecases/persona-reviews.md +0 -0
  77. /package/{doc → docs}/philosophy.md +0 -0
@@ -0,0 +1,369 @@
1
+ // Resolves selected skill IDs, validates references, and materializes generated skills.
2
+ import { copyFileSync, cpSync, existsSync, globSync, mkdirSync, readdirSync, realpathSync, statSync, } from 'node:fs';
3
+ import { basename, isAbsolute, join, relative, sep } from 'node:path';
4
+ import { isSkillDocumentIssue, isValidSkillId, readSkillDocument, skillMaterializationSections, } from './SkillDocument.js';
5
+ export const resolveSkillEntries = (input) => {
6
+ const sources = [];
7
+ const diagnostics = [];
8
+ for (const entryInput of input.entries) {
9
+ const outcome = resolveSkillEntry(input, entryInput);
10
+ sources.push(...outcome.sources);
11
+ diagnostics.push(...outcome.diagnostics);
12
+ }
13
+ return { sources, diagnostics };
14
+ };
15
+ const resolveSkillEntry = (input, entryInput) => {
16
+ const { entry, profileReferenceRoot } = entryInput;
17
+ const selection = typeof entry === 'string' ? { id: entry } : entry;
18
+ const catalogEntry = input.catalog.entries.get(selection.id);
19
+ if (catalogEntry === undefined) {
20
+ return resolveUncataloguedEntry(entry, selection.id);
21
+ }
22
+ const references = selection.references ?? [];
23
+ const referencesKey = JSON.stringify(references);
24
+ const cached = input.materializationCache?.get(selection.id);
25
+ if (cached !== undefined) {
26
+ return resolveCachedEntry(cached, referencesKey, selection.id);
27
+ }
28
+ const resolved = resolveCatalogSkill({
29
+ catalogEntry,
30
+ references,
31
+ profileReferenceRoot,
32
+ projectDirectory: input.projectDirectory,
33
+ outputDirectory: input.outputDirectory,
34
+ });
35
+ input.materializationCache?.set(selection.id, {
36
+ referencesKey,
37
+ generatedDirectory: resolved.generatedDirectory,
38
+ });
39
+ return { sources: toEntrySources(resolved.generatedDirectory), diagnostics: resolved.diagnostics };
40
+ };
41
+ const resolveCachedEntry = (cached, referencesKey, id) => {
42
+ if (cached.referencesKey !== referencesKey) {
43
+ return {
44
+ sources: [],
45
+ diagnostics: [
46
+ {
47
+ severity: 'error',
48
+ path: `controls.skills/${id}`,
49
+ message: `Skill '${id}' is selected with conflicting reference sets across control scopes.`,
50
+ },
51
+ ],
52
+ };
53
+ }
54
+ return { sources: toEntrySources(cached.generatedDirectory), diagnostics: [] };
55
+ };
56
+ const toEntrySources = (generatedDirectory) => generatedDirectory === undefined ? [] : [generatedDirectory];
57
+ const resolveUncataloguedEntry = (entry, id) => {
58
+ if (typeof entry !== 'string') {
59
+ return {
60
+ sources: [],
61
+ diagnostics: [
62
+ {
63
+ severity: 'error',
64
+ path: `controls.skills/${id}`,
65
+ message: `Skill ID '${id}' does not resolve in any skills directory.`,
66
+ },
67
+ ],
68
+ };
69
+ }
70
+ if (isValidSkillId(entry)) {
71
+ return {
72
+ sources: [entry],
73
+ diagnostics: [
74
+ {
75
+ severity: 'warning',
76
+ path: `controls.skills/${entry}`,
77
+ message: `Skill '${entry}' does not resolve in any skills directory; passing it through as a path source.`,
78
+ },
79
+ ],
80
+ };
81
+ }
82
+ return { sources: [entry], diagnostics: [] };
83
+ };
84
+ const resolveCatalogSkill = (input) => {
85
+ const { catalogEntry } = input;
86
+ const diagnostics = [];
87
+ const document = readSkillDocument(catalogEntry.skillPath);
88
+ if (isSkillDocumentIssue(document)) {
89
+ return { diagnostics: [{ severity: 'error', path: document.path, message: document.message }] };
90
+ }
91
+ if (document.name !== catalogEntry.id) {
92
+ return {
93
+ diagnostics: [
94
+ {
95
+ severity: 'error',
96
+ path: catalogEntry.skillPath,
97
+ message: `SKILL.md 'name' ('${document.name}') must match its directory name ('${catalogEntry.id}').`,
98
+ },
99
+ ],
100
+ };
101
+ }
102
+ const materializations = planSkillMaterializations(input, document, diagnostics);
103
+ if (diagnostics.some((diagnostic) => diagnostic.severity === 'error') || input.outputDirectory === undefined) {
104
+ return { diagnostics };
105
+ }
106
+ const generatedDirectory = join(input.outputDirectory, catalogEntry.id);
107
+ cpSync(catalogEntry.directory, generatedDirectory, { recursive: true });
108
+ for (const materialization of materializations) {
109
+ const sectionDirectory = join(generatedDirectory, materialization.section);
110
+ mkdirSync(sectionDirectory, { recursive: true });
111
+ const destinationPath = join(sectionDirectory, materialization.destinationName);
112
+ // Both copies preserve the source mode, so materialized scripts stay
113
+ // executable. Directory targets dereference symlinks that the contained
114
+ // scan already validated, so the generated skill is self-contained.
115
+ if (materialization.kind === 'directory') {
116
+ copyDirectoryDereferenced(materialization.sourcePath, destinationPath);
117
+ }
118
+ else {
119
+ copyFileSync(materialization.sourcePath, destinationPath);
120
+ }
121
+ }
122
+ return { generatedDirectory, diagnostics };
123
+ };
124
+ const planSkillMaterializations = (input, document, diagnostics) => {
125
+ const materializations = [];
126
+ for (const section of skillMaterializationSections) {
127
+ const entries = [
128
+ ...document[section].map((reference) => ({ reference, fileRoot: input.catalogEntry.referenceRoot })),
129
+ // Profile-added references resolve `file` from the declaring profile's repository.
130
+ ...(section === 'references'
131
+ ? input.references.map((reference) => ({
132
+ reference,
133
+ fileRoot: input.profileReferenceRoot ?? input.projectDirectory ?? input.catalogEntry.referenceRoot,
134
+ }))
135
+ : []),
136
+ ];
137
+ materializations.push(...planSectionMaterializations(input, section, entries, diagnostics));
138
+ }
139
+ return materializations;
140
+ };
141
+ const planSectionMaterializations = (input, section, entries, diagnostics) => {
142
+ const materializations = [];
143
+ const destinationSources = new Map();
144
+ for (const { reference, fileRoot } of entries) {
145
+ const outcomes = resolveReferenceMaterializations({
146
+ reference,
147
+ section,
148
+ fileRoot,
149
+ projectDirectory: input.projectDirectory,
150
+ skillPath: input.catalogEntry.skillPath,
151
+ });
152
+ for (const resolved of outcomes) {
153
+ if ('message' in resolved) {
154
+ diagnostics.push(resolved);
155
+ continue;
156
+ }
157
+ const collision = describeDestinationCollision(input, section, resolved, destinationSources);
158
+ if (collision !== undefined) {
159
+ diagnostics.push({ severity: 'error', path: input.catalogEntry.skillPath, message: collision });
160
+ continue;
161
+ }
162
+ destinationSources.set(resolved.destinationName, resolved.sourcePath);
163
+ materializations.push(resolved);
164
+ }
165
+ }
166
+ return materializations;
167
+ };
168
+ /** Reports a destination claimed twice or already shipped inside the skill directory. */
169
+ const describeDestinationCollision = (input, section, resolved, destinationSources) => {
170
+ const previousSource = destinationSources.get(resolved.destinationName);
171
+ if (previousSource !== undefined) {
172
+ return (`Destination '${section}/${resolved.destinationName}' is declared more than once ` +
173
+ `(by '${previousSource}' and '${resolved.sourcePath}').`);
174
+ }
175
+ // Checked against the source skill directory during planning so lint reports
176
+ // shipped-file collisions without materializing anything.
177
+ if (existsSync(join(input.catalogEntry.directory, section, resolved.destinationName))) {
178
+ return (`Destination '${section}/${resolved.destinationName}' collides with a file ` +
179
+ `already shipped by skill '${input.catalogEntry.id}'.`);
180
+ }
181
+ return undefined;
182
+ };
183
+ const describeReference = (reference, fileRoot, projectDirectory) => 'repo_file' in reference
184
+ ? { declaredPath: reference.repo_file, root: projectDirectory, kind: 'repo_file', rootLabel: 'project' }
185
+ : { declaredPath: reference.file, root: fileRoot, kind: 'file', rootLabel: 'catalog' };
186
+ const targetError = (skillPath, message) => ({
187
+ severity: 'error',
188
+ path: skillPath,
189
+ message,
190
+ });
191
+ /**
192
+ * Resolves one reference entry to its materializations: one for a literal
193
+ * target, one per match for a glob target, and none for an omitted missing
194
+ * `repo_file` target.
195
+ */
196
+ const resolveReferenceMaterializations = (input) => {
197
+ const { declaredPath, root, kind, rootLabel } = describeReference(input.reference, input.fileRoot, input.projectDirectory);
198
+ if (root === undefined) {
199
+ return [
200
+ targetError(input.skillPath, `Reference ${kind} '${declaredPath}' has no ${rootLabel} root to resolve from.`),
201
+ ];
202
+ }
203
+ const context = { root, kind, rootLabel, section: input.section, skillPath: input.skillPath };
204
+ if (isGlobPattern(declaredPath)) {
205
+ return expandGlobMaterializations(declaredPath, context);
206
+ }
207
+ const resolved = resolveTargetMaterialization(declaredPath, context);
208
+ return resolved === undefined ? [] : [resolved];
209
+ };
210
+ /**
211
+ * Matches when a target uses glob syntax instead of naming one literal path.
212
+ * Only the gitignore-style metacharacters count; braces are literal path
213
+ * characters, so a braced filename resolves as a literal target.
214
+ */
215
+ const isGlobPattern = (declaredPath) => /[*?[]/u.test(declaredPath);
216
+ /**
217
+ * Expands a glob target against its root. Each match then follows the same
218
+ * rules as a literal target, so a matched directory materializes recursively
219
+ * while an escaping or special match fails validation individually.
220
+ */
221
+ const expandGlobMaterializations = (pattern, context) => {
222
+ // Braces are literal path characters in this contract, but globSync
223
+ // brace-expands them textually and offers no escape, so mixing them with
224
+ // glob syntax fails validation rather than silently matching other paths.
225
+ if (/[{}]/u.test(pattern)) {
226
+ return [
227
+ targetError(context.skillPath, `Reference ${context.kind} glob '${pattern}' must not contain braces; ` +
228
+ `braces are literal path characters, not glob syntax.`),
229
+ ];
230
+ }
231
+ // Sorted so diagnostics and collisions are deterministic across platforms.
232
+ const matches = globSync(pattern, { cwd: context.root }).sort();
233
+ if (matches.length === 0) {
234
+ // A consuming project may not contain repo_file matches; the reference is omitted.
235
+ return context.kind === 'repo_file'
236
+ ? []
237
+ : [targetError(context.skillPath, `Reference file glob '${pattern}' matched no files under '${context.root}'.`)];
238
+ }
239
+ const resolved = [];
240
+ for (const match of matches) {
241
+ const outcome = resolveTargetMaterialization(match, context);
242
+ if (outcome !== undefined) {
243
+ resolved.push(outcome);
244
+ }
245
+ }
246
+ return resolved;
247
+ };
248
+ /** Validates one concrete target path — a literal target or a single glob match. */
249
+ const resolveTargetMaterialization = (targetPath, context) => {
250
+ const { root, kind, rootLabel, skillPath } = context;
251
+ const error = (message) => targetError(skillPath, message);
252
+ const sourcePath = isAbsolute(targetPath) ? targetPath : join(root, targetPath);
253
+ if (!existsSync(sourcePath)) {
254
+ // A consuming project may not contain a repo_file target; the reference is omitted.
255
+ return kind === 'repo_file' ? undefined : error(`Reference file '${targetPath}' was not found under '${root}'.`);
256
+ }
257
+ const stats = statSync(sourcePath);
258
+ if (!stats.isFile() && !stats.isDirectory()) {
259
+ return error(`Reference ${kind} '${targetPath}' must be a regular file or directory.`);
260
+ }
261
+ if (escapesRoot(sourcePath, root)) {
262
+ return error(`Reference ${kind} '${targetPath}' resolves outside its ${rootLabel} root '${root}'.`);
263
+ }
264
+ const directoryIssue = describeDirectoryTargetIssue(stats, sourcePath, targetPath, context);
265
+ if (directoryIssue !== undefined) {
266
+ return error(directoryIssue);
267
+ }
268
+ return {
269
+ section: context.section,
270
+ sourcePath,
271
+ destinationName: basename(targetPath),
272
+ kind: stats.isDirectory() ? 'directory' : 'file',
273
+ };
274
+ };
275
+ /** Describes the first escaping, cyclic, or special path inside a directory target, if any. */
276
+ const describeDirectoryTargetIssue = (stats, sourcePath, targetPath, context) => {
277
+ if (!stats.isDirectory()) {
278
+ return undefined;
279
+ }
280
+ const issue = scanDirectoryTarget(sourcePath, context.root, [realpathSync(sourcePath)], new Set());
281
+ if (issue === undefined) {
282
+ return undefined;
283
+ }
284
+ const containedPath = relative(sourcePath, issue.path);
285
+ const problemDescriptions = {
286
+ escaping: `which resolves outside its ${context.rootLabel} root '${context.root}'`,
287
+ cyclic: 'which creates a symlink cycle',
288
+ special: 'which is not a regular file or directory',
289
+ };
290
+ return (`Reference ${context.kind} '${targetPath}' contains ` + `'${containedPath}', ${problemDescriptions[issue.problem]}.`);
291
+ };
292
+ /**
293
+ * Finds the first path inside a directory target whose realpath escapes the
294
+ * reference root, a symlink that cycles back into an ancestor directory, or an
295
+ * entry that is neither a regular file nor a directory. Directory
296
+ * materialization dereferences symlinks recursively, so an escaping link would
297
+ * smuggle outside content into the generated skill, a cyclic link would never
298
+ * finish copying, and a special file such as a FIFO could block the copy.
299
+ */
300
+ const scanDirectoryTarget = (directory, root,
301
+ /** Realpaths of the directories on the current descent, for cycle detection. */
302
+ ancestry,
303
+ /** Realpaths of fully scanned directories, so shared subtrees scan once. */
304
+ scanned) => {
305
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
306
+ const entryPath = join(directory, entry.name);
307
+ if (escapesRoot(entryPath, root)) {
308
+ return { path: entryPath, problem: 'escaping' };
309
+ }
310
+ // statSync follows symlinks, so in-root symlinked subdirectories are
311
+ // scanned too and a link to a special file is rejected like the file itself.
312
+ const entryStats = statSync(entryPath);
313
+ if (!entryStats.isFile() && !entryStats.isDirectory()) {
314
+ return { path: entryPath, problem: 'special' };
315
+ }
316
+ if (!entryStats.isDirectory()) {
317
+ continue;
318
+ }
319
+ const resolvedEntryPath = realpathSync(entryPath);
320
+ if (ancestry.includes(resolvedEntryPath)) {
321
+ return { path: entryPath, problem: 'cyclic' };
322
+ }
323
+ if (!scanned.has(resolvedEntryPath)) {
324
+ scanned.add(resolvedEntryPath);
325
+ const issue = scanDirectoryTarget(entryPath, root, [...ancestry, resolvedEntryPath], scanned);
326
+ if (issue !== undefined) {
327
+ return issue;
328
+ }
329
+ }
330
+ }
331
+ return undefined;
332
+ };
333
+ /**
334
+ * Copies a directory target while dereferencing symlinks, so the generated
335
+ * skill has no links back into catalog or project checkouts. cpSync's
336
+ * dereference option only follows the top-level source path, so nested entries
337
+ * are walked explicitly; copyFileSync preserves each file's mode.
338
+ */
339
+ const copyDirectoryDereferenced = (source, destination) => {
340
+ mkdirSync(destination, { recursive: true });
341
+ for (const entry of readdirSync(source, { withFileTypes: true })) {
342
+ const sourcePath = join(source, entry.name);
343
+ const destinationPath = join(destination, entry.name);
344
+ // statSync follows symlinks; scanDirectoryTarget already rejected cycles.
345
+ if (statSync(sourcePath).isDirectory()) {
346
+ copyDirectoryDereferenced(sourcePath, destinationPath);
347
+ }
348
+ else {
349
+ copyFileSync(sourcePath, destinationPath);
350
+ }
351
+ }
352
+ };
353
+ /** Targets must remain within their root after following symlinks. */
354
+ const escapesRoot = (sourcePath, root) => {
355
+ let resolvedSource;
356
+ let resolvedRoot;
357
+ try {
358
+ resolvedSource = realpathSync(sourcePath);
359
+ resolvedRoot = realpathSync(root);
360
+ }
361
+ catch {
362
+ /* v8 ignore next 2 -- existsSync guards the source; a vanished root is a race we treat as escaping. */
363
+ return true;
364
+ }
365
+ const relativePath = relative(resolvedRoot, resolvedSource);
366
+ // A bare '..' or a '../' prefix escapes; a sibling name like '..config' does not.
367
+ return relativePath === '..' || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath);
368
+ };
369
+ //# sourceMappingURL=SkillResolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillResolution.js","sourceRoot":"","sources":["../../src/skills/SkillResolution.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,11 @@ User-facing Outfitter documentation.
8
8
  - [First-time CLI agent users](./first-time-cli-agent-users.md)
9
9
  - [Switching to Outfitter](./switching-to-outfitter.md)
10
10
  - [Profiles](./profiles.md)
11
- - [Profile repositories](./profile-repository.md)
11
+ - [Skills](./skills.md) — Define project and profile-bundled skills, route to specialized resources, and compose external references.
12
+ - [Best practices](./best-practices.md) — Prefer a few stable profiles and many focused, progressively disclosed skills.
13
+ - [Profile repositories](./profile-repository.md) — Publish and consume shareable profiles and standalone skills.
12
14
  - [Iterating on local and worktree profiles](./iterating-on-profiles.md)
15
+ - [Running profiles in GitHub Actions](./actions.md)
13
16
  - [Adapter support matrix](./support-matrix.md)
14
17
  - [State persistence](./state.md)
15
18
  - [Philosophy](../philosophy.md)
@@ -0,0 +1,97 @@
1
+ # Running profiles in GitHub Actions
2
+
3
+ [`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) runs an Outfitter profile non-interactively inside a GitHub Actions workflow. Outfitter assembles the profile exactly as it does locally — context, prompts, skills, controls — and launches the agent CLI in headless print mode (`pi -p`), so the agent does one unit of work per workflow run and exits. Wire it to any trigger and a profile becomes a CI agent: a PR reviewer, a scheduled commit auditor, an issue triager.
4
+
5
+ ```yaml
6
+ # .github/workflows/issue-triage.yml
7
+ name: Issue triage
8
+ on:
9
+ issues:
10
+ types: [opened]
11
+
12
+ permissions:
13
+ contents: read
14
+ issues: write
15
+ models: read
16
+
17
+ jobs:
18
+ triage:
19
+ if: github.event.issue.user.type != 'Bot'
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: ai-outfitter/actions@v1
24
+ with:
25
+ profile: issue-triage
26
+ profile-source: ${{ github.workspace }}/profiles
27
+ prompt: >-
28
+ Triage issue #${{ github.event.issue.number }} in
29
+ ${{ github.repository }} following your process.
30
+ ```
31
+
32
+ The action installs `@ai-outfitter/outfitter`, writes a minimal `~/.outfitter/settings.yml` on the runner, syncs remote catalogs if needed, then runs `outfitter run --profile <profile> --agent pi -- -p "<prompt>"`. The runner is discarded afterwards; nothing persists except what the agent pushed through its token.
33
+
34
+ Profiles can come from the checked-out repository itself (a path, as above), an `owner/repo` catalog shorthand, or any git URI — the same [profile repository](./profile-repository.md) sources Outfitter supports locally. Pin `profile-source-ref` for catalogs you don't own.
35
+
36
+ ## Pass GitHub trigger context
37
+
38
+ `trigger_context` is a convention for the initial prompt passed by an
39
+ `ai-outfitter/actions` workflow. It is not an Outfitter object and Outfitter does
40
+ not create or parse it. GitHub Actions interpolates the selected `github`
41
+ expression values before invoking Outfitter, giving the profile metadata that
42
+ the workflow — not the event author — chose to pass. That does not make every
43
+ value trustworthy: branch and tag names, labels, titles, and logins are
44
+ user-influenced, so route on them as opaque identifiers and never treat them
45
+ as instructions.
46
+
47
+ ```yaml
48
+ - uses: ai-outfitter/actions@v1
49
+ with:
50
+ profile: platform
51
+ prompt: |
52
+ Handle this GitHub event according to the profile's skill activation rules.
53
+
54
+ trigger_context:
55
+ repository: ${{ github.repository }}
56
+ event_name: ${{ github.event_name }}
57
+ issue_number: ${{ github.event.issue.number || '' }}
58
+ ```
59
+
60
+ Include only the identifiers the profile's routing rules need for the
61
+ workflow's declared events (for example `sha`, `issue_labels`, or a
62
+ deployment's `environment_url` when those events are in play). Add a
63
+ workflow-owned discriminator, such as `report_kind: weekly-kpi`, when GitHub's
64
+ event metadata cannot distinguish scheduled behaviors.
65
+
66
+ Keep the profile's mapping from this metadata to skills short and keep task
67
+ procedures in the skills themselves. See
68
+ [Keep routing concise](./best-practices.md#keep-routing-concise) for that design
69
+ boundary.
70
+
71
+ Do not interpolate issue bodies, pull request bodies, comments, diffs,
72
+ deployment logs, or fetched page content into `trigger_context`. Pass stable
73
+ identifiers, select the relevant skill, and let that skill retrieve only the
74
+ untrusted source material it needs with trusted tools.
75
+
76
+ ## Zero-key inference with GitHub Models
77
+
78
+ CI agents don't need a paid provider key. [GitHub Models](https://docs.github.com/en/github-models) serves hosted models authenticated by the workflow's own `GITHUB_TOKEN`: grant `models: read` in the `permissions:` block, commit a pi provider config pointing at `https://models.github.ai/inference` with `"apiKey": "$GITHUB_TOKEN"`, install it to `~/.pi/agent/models.json` before the action step, and select the provider in the profile's `controls`. The action's README documents the full recipe, including model-selection gotchas (catalog availability, tool-call wire compatibility, and models too weak to hold an agentic loop).
79
+
80
+ Mind the rate limits: the included tier is sized for event-driven, one-shot jobs. Concurrent runs of a large model can 429; high-volume review loops need a provider key.
81
+
82
+ ## Write profiles for headless runs
83
+
84
+ A profile that behaves well interactively can still fail silently in CI. Lessons from running triage agents in production:
85
+
86
+ - **Stdout is invisible.** In print mode nobody reads what the agent says — only its side effects matter. Instruct the profile to _do_ things with `gh` (comment, label, push) and name the exact commands; otherwise models will print the deliverable as their answer and exit green.
87
+ - **Quote-safe posting.** When the agent posts text derived from untrusted input (issue bodies, diffs) back through `gh`, require a quoted heredoc plus `--body-file`, never inline `--body "..."` — backticks in a double-quoted body are executed by the shell.
88
+ - **Verify side effects, not exit codes.** A green run is not proof of work. Add a post-agent step that asserts the expected side effects landed — the action ships [`scripts/validate-triage.sh`](https://github.com/ai-outfitter/actions/blob/main/scripts/validate-triage.sh) as a reference for triage-style jobs.
89
+ - **Hard limits in the profile.** Enumerate exactly what the agent may do (which labels, how many comments, no closing/editing) and treat fetched content as data to classify, never instructions.
90
+
91
+ ## Scope the token
92
+
93
+ The agent runs arbitrary `gh`/`git`/shell with whatever token you hand it, against untrusted input. Prefer the workflow's own `GITHUB_TOKEN` with an explicit least-privilege `permissions:` block; use a fine-grained PAT from a dedicated machine account only when the agent needs its own identity. Never use a human's PAT. The action's [token-permissions](https://github.com/ai-outfitter/actions/blob/main/docs/token-permissions.md) and [bot-account](https://github.com/ai-outfitter/actions/blob/main/docs/bot-account.md) guides cover this in depth, including prompt-injection trust boundaries.
94
+
95
+ ## More examples
96
+
97
+ The action's [`examples/`](https://github.com/ai-outfitter/actions/tree/main/examples) directory covers scheduled commit review, PR ready-for-review reviews, sensitive-path audits, assigned-task agents, and zero-key issue triage on GitHub Models. A complete live setup — workflow, profile, provider config, and validation — runs in [`ai-outfitter/default-profiles`](https://github.com/ai-outfitter/default-profiles) as its own issue-triage agent.
@@ -0,0 +1,105 @@
1
+ # Best practices
2
+
3
+ Outfitter works best with a few stable profiles and many focused skills.
4
+ Profiles define who the agent is and the boundaries it operates within. Skills
5
+ define what the agent can progressively learn to do.
6
+
7
+ ## Prefer a few profiles and many skills
8
+
9
+ Create a profile for a durable identity or policy boundary — engineering,
10
+ platform operations, support, a customer persona. A profile owns model and
11
+ provider controls, operating policy and safety boundaries, tools and
12
+ permissions, conventions, and the short rules for selecting skills.
13
+
14
+ Add a skill when the new behavior is a capability within an existing identity:
15
+ issue planning, code review, deployment smoke testing, KPI reporting, release
16
+ preparation. Adding a new situation SHOULD usually add a skill and a concise
17
+ activation rule, not another profile. Reserve profile inheritance for genuine
18
+ control and policy composition; do not require consumers to inherit a profile
19
+ merely to access one of its skills.
20
+
21
+ Prefer one profile with many skills:
22
+
23
+ ```text
24
+ platform profile
25
+ ├── issue-planning skill
26
+ ├── issue-implementation skill
27
+ ├── kpi-reporting skill
28
+ ├── deployment-review skill
29
+ └── failed-deployment-triage skill
30
+ ```
31
+
32
+ Avoid separate `issue-planner`, `deployment-reviewer`, and `kpi-reporter`
33
+ profiles when they share the same platform identity, permissions, and tools.
34
+ Adding release notes later should add a `release-notes` skill to the platform
35
+ profile, not a `release-notes-agent` profile with copies of the same controls.
36
+
37
+ Separate profiles are appropriate when the policy boundary differs. An
38
+ engineering agent may edit code, run tests, and push branches; a customer
39
+ support agent may read customer conversations and draft replies but must not
40
+ modify repositories. Those are different identities with different data access,
41
+ tools, and write permissions, so separate `engineering` and `support` profiles
42
+ are appropriate — and each can still expose many focused skills.
43
+
44
+ ## Keep skills focused
45
+
46
+ Give each skill one recognizable capability and a description precise enough
47
+ for an agent to decide when it applies. Keep common policy in the profile
48
+ rather than repeating it across every skill.
49
+
50
+ Focused does not mean tiny. Err on the side of one larger skill that
51
+ [routes to different references](./skills.md#skills-as-routers) over many
52
+ near-duplicate skills: split a skill only when its description can no longer
53
+ say when it applies. Point references at existing human-maintained
54
+ documentation rather than writing new agent-only copies, and use
55
+ [profile-added references](./skills.md#profile-added-references) to specialize
56
+ a shared skill instead of forking it.
57
+
58
+ ## Use references for human documentation
59
+
60
+ Keep canonical architecture, policy, and operating documents in normal `docs/`
61
+ locations where people already maintain and review them. Declare those files as
62
+ skill `references` instead of copying them into skill directories, and read
63
+ them only after the skill activates so every run does not pay the context cost
64
+ of every possible workflow. See
65
+ [External references](./skills.md#external-references) for the reference format
66
+ and trust rules.
67
+
68
+ ## Keep routing concise
69
+
70
+ A profile's system prompt can map stable runtime signals to relevant skills.
71
+ Keep these activation rules short; detailed procedures belong in the selected
72
+ skills and their references, never repeated in the profile prompt (see
73
+ [Where context and instructions live](./skills.md#where-context-and-instructions-live)).
74
+
75
+ ```text
76
+ Select only the skill relevant to the current task.
77
+ - Planning request: use issue-planning.
78
+ - Approved implementation request: use issue-implementation.
79
+ - Recurring repository activity report: use kpi-reporting.
80
+ - Successful environment awaiting verification: use deployment-review.
81
+ - Failed environment update: use failed-deployment-triage.
82
+ Load detailed task content only after selecting the skill.
83
+ ```
84
+
85
+ When an integration launches the profile, pass only the trusted identifiers and
86
+ runtime metadata needed to choose a skill. Keep untrusted source material out
87
+ of the activation rules and let the selected skill retrieve only what it needs
88
+ with trusted tools.
89
+
90
+ ## Keep automation reusable
91
+
92
+ For agentic automation, prefer a small number of reusable workflows that pass
93
+ concise runtime metadata to the same stable execution profile. Let that profile
94
+ activate the appropriate skill. One profile and one workflow can then support
95
+ issue planning, implementation, scheduled reporting, deployment review, and
96
+ future situations; adding a capability becomes a skill change instead of
97
+ another near-duplicate profile and automation job.
98
+
99
+ ## Review the trust chain
100
+
101
+ Profiles and skills can influence agent behavior and tool use. Follow
102
+ [Trust and review](./profile-repository.md#trust-and-review) for catalog
103
+ sources, keep secrets out of profiles, skills, references, and prompts, and run
104
+ `outfitter profile lint --strict` in CI to catch broken skill IDs and
105
+ references before they reach an agent run.