facult 2.8.12 → 2.10.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.
package/README.md CHANGED
@@ -127,7 +127,7 @@ fclt index
127
127
 
128
128
  Why `keep-current`: it is deterministic and non-interactive for duplicate sources.
129
129
 
130
- ### 4. Manage a tool and sync
130
+ ### 4. Optional: manage a tool and sync
131
131
 
132
132
  ```bash
133
133
  fclt manage codex --dry-run
@@ -140,7 +140,11 @@ fclt enable requesting-code-review receiving-code-review brainstorming systemati
140
140
  fclt sync
141
141
  ```
142
142
 
143
- Use `--dry-run` first if the live tool already has local content. If the tool already contains skills, agents, rules, docs, config, or MCP definitions, rerun with `--adopt-existing` and add `--existing-conflicts keep-canonical|keep-existing` if names collide.
143
+ Managed rendering is an advanced mode. Prefer `fclt inventory`, `fclt list`, `fclt consolidate`, and explicit writeback/evolution when you mainly want visibility and normalization across Codex, Claude, and other tool homes. Use `manage` only when you want fclt to write rendered files back into a tool.
144
+
145
+ Use `--dry-run` first if the live tool already has local content. If the tool already contains skills, agents, rules, docs, config, or MCP definitions, rerun `manage` with `--adopt-existing` and add `--existing-conflicts keep-canonical|keep-existing` if names collide.
146
+
147
+ Ordinary `fclt sync` does not import live tool edits into canonical state. If you intentionally edited skills, agents, docs, rules, config, or MCP entries in Codex/Claude and want fclt to pick them up, run `fclt sync --adopt-live`.
144
148
 
145
149
  Codex path policy:
146
150
  - skills render to `.agents/skills`
@@ -200,6 +204,8 @@ Useful AI behavior is composable. You need small reusable parts, a clean way to
200
204
  - discovery and graph views for dependencies, provenance, and rendered targets
201
205
  - writeback and evolution flows for improving canonical assets over time
202
206
 
207
+ The renderer is optional. The low-friction default is to let tools keep their native files, use `fclt inventory`/`scan`/`list` to see the full global set, and use `fclt consolidate` or `fclt sync --adopt-live` only when you explicitly want to promote live tool edits into canonical `~/.ai`.
208
+
203
209
  ## Built-in Defaults
204
210
 
205
211
  `fclt` includes a built-in layer for writeback and evolution. By default, that layer provides:
@@ -231,9 +237,10 @@ Put that in `config.toml` or `config.local.toml` under the active canonical root
231
237
 
232
238
  `fclt` is CLI-first. The practical setup is:
233
239
  1. Install `fclt` globally so any agent runtime can execute it.
234
- 2. Manage each agent tool with `fclt manage <tool>` and `fclt sync`.
235
- 3. Let the built-in operating-model layer render global writeback/evolution instructions into the tool.
236
- 4. Optionally scaffold MCP wrappers if you want an MCP entry that delegates to `fclt`.
240
+ 2. Use `fclt inventory`, `fclt list`, and `fclt consolidate` to inspect and normalize existing tool-native state.
241
+ 3. If you want fclt-owned rendered outputs, manage each agent tool with `fclt manage <tool>` and `fclt sync`.
242
+ 4. Let the built-in operating-model layer render global writeback/evolution instructions into the tool only where managed rendering is worth the ownership tradeoff.
243
+ 5. Optionally scaffold MCP wrappers if you want an MCP entry that delegates to `fclt`.
237
244
 
238
245
  ```bash
239
246
  # Scaffold reusable templates in the canonical store
@@ -450,14 +457,18 @@ fclt ai evolve apply EV-00001
450
457
  fclt ai evolve promote EV-00003 --to global --project
451
458
  ```
452
459
 
453
- Runtime writeback and evolution state stays generated and machine-local:
460
+ Runtime writeback and evolution source state stays generated and machine-local:
454
461
  - global writeback state: machine-local Facult state under `.../global/ai/global/...`
455
462
  - project writeback state: machine-local per-project Facult state under `.../projects/<slug-hash>/ai/project/...`
463
+ - editor-facing writeback review artifacts: `~/.ai/writebacks/global/*.md` and `~/.ai/writebacks/projects/<slug-hash>/*.md`
464
+ - editor-facing evolution review artifacts: `~/.ai/evolution/global/*.md` and `~/.ai/evolution/projects/<slug-hash>/*.md`
456
465
 
457
466
  That split is intentional:
458
467
  - canonical source remains in `~/.ai` or `<repo>/.ai`
459
- - global generated index and graph state stays inside `~/.ai/.facult/`; writebacks, journals, proposals, drafts, and managed runtime state stay outside canonical source in machine-local state
460
- - those records let agents inspect what changed, why it changed, and how it was reviewed
468
+ - global generated index and graph state stays inside `~/.ai/.facult/`; JSON queues, proposal metadata, journals, draft refs, patches, and managed runtime state stay outside canonical source in machine-local state
469
+ - human-readable review artifacts always live under the global `~/.ai` root, even when the signal is project-scoped
470
+ - project repos do not receive bundled writeback/evolution review artifacts; project metadata such as cwd, project root, project slug, target refs, status, and evidence is captured in frontmatter instead
471
+ - those records let agents and humans inspect what changed, why it changed, and how it was reviewed
461
472
 
462
473
  Use writeback when:
463
474
  - a task exposed a weak or misleading verification loop
@@ -485,12 +496,14 @@ Current apply semantics are intentionally policy-bound:
485
496
 
486
497
  Current review/draft semantics:
487
498
  - `writeback group` and `writeback summarize` expose recurring patterns across `asset`, `kind`, and `domain` without mutating canonical assets
488
- - drafted proposals emit both a human-readable markdown draft and a patch artifact under generated state
499
+ - every writeback/proposal mutation refreshes a Markdown review artifact under global `~/.ai/writebacks/...` or `~/.ai/evolution/...` with frontmatter metadata
500
+ - drafted proposals emit both a human-readable markdown draft and a patch artifact under machine-local generated state, and the latest draft body is mirrored into the global evolution review artifact
489
501
  - rerunning `evolve draft <id> --append ...` revises the draft and records draft history
490
502
  - `evolve promote --to global` creates a new high-risk global proposal from a project-scoped proposal; that promoted proposal can then be drafted, reviewed, and applied into `~/.ai`
491
503
 
492
504
  Review surfaces:
493
- - `fclt status --json` reports queue/proposal paths and counts for the active scope
505
+ - open `~/.ai/writebacks/` and `~/.ai/evolution/` in a Markdown editor for global and project-scoped review artifacts
506
+ - `fclt status --json` reports queue/proposal paths, review artifact paths, and counts for the active scope
494
507
  - `fclt ai writeback list|show|group|summarize` reviews raw and clustered signal
495
508
  - `fclt ai evolve list|show|review` reviews proposal state without applying changes
496
509
  - `fclt templates init automation learning-review` scaffolds background writeback capture/review
@@ -586,7 +599,7 @@ fclt disable <name> [--for <tool1,tool2,...>]
586
599
  fclt trust --all
587
600
  fclt trust skills --all
588
601
  fclt untrust mcp --all
589
- fclt sync [tool] [--dry-run] [--builtin-conflicts overwrite]
602
+ fclt sync [tool] [--dry-run] [--adopt-live] [--builtin-conflicts overwrite]
590
603
  fclt autosync install [tool] [--git-remote <name>] [--git-branch <name>] [--git-interval-minutes <n>] [--git-disable]
591
604
  fclt autosync status [tool]
592
605
  fclt autosync restart [tool]
@@ -635,7 +648,7 @@ fclt snippets sync [--dry-run] [file...]
635
648
 
636
649
  Recommended topology:
637
650
 
638
- - Use `learning-review --scope project` for repo-local writeback and evolution. This keeps review state, verification, and follow-up scoped to the repo that actually produced the evidence.
651
+ - Use `learning-review --scope project` for project-scoped writeback and evolution. This keeps verification and follow-up scoped to the repo that produced the evidence while storing human-readable review artifacts under global `~/.ai/writebacks/projects/...` and `~/.ai/evolution/projects/...`.
639
652
  - Use `evolution-review` on a slower cadence, usually weekly, to triage open proposals and proposal-worthy clusters and suggest the next operator action (`draft`, `review`, `accept`, `reject`, `promote`, or `apply`).
640
653
  - Use a separate wide/global automation only for cross-repo or shared-surface review, such as global doctrine, shared skills, or repeated tool/agent patterns across repos.
641
654
  - If you do use a wide learning review, keep the `cwds` list intentionally small and related. The prompt is designed to partition by cwd first, not to blur unrelated repos together.
@@ -734,6 +747,10 @@ Under machine-local Facult state:
734
747
  - `cache/runtime/<version>/<platform-arch>/...` under the macOS machine-local state root, or `runtime/<version>/<platform-arch>/...` under `FACULT_CACHE_DIR`/XDG cache roots on other platforms (npm launcher binary cache)
735
748
  - if that cache root is unavailable, the npm launcher falls back to a temp-dir runtime cache before using the bundled source fallback
736
749
 
750
+ Under global Markdown review state (`~/.ai/`):
751
+ - `writebacks/global/*.md` and `writebacks/projects/<slug-hash>/*.md` (frontmatter-rich writeback review artifacts)
752
+ - `evolution/global/*.md` and `evolution/projects/<slug-hash>/*.md` (frontmatter-rich proposal review artifacts, including latest draft body when present)
753
+
737
754
  ### Config reference
738
755
 
739
756
  `~/.ai/.facult/config.json` supports:
@@ -78,7 +78,8 @@ Use `fclt ai evolve draft <id> --append "..."` to revise a draft while preservin
78
78
 
79
79
  Review surfaces:
80
80
 
81
- - `fclt status --json` for queue/proposal paths, counts, and active scope
81
+ - open `~/.ai/writebacks/` and `~/.ai/evolution/` in a Markdown editor for frontmatter-rich global and project-scoped review artifacts
82
+ - `fclt status --json` for queue/proposal paths, review artifact paths, counts, and active scope
82
83
  - `fclt ai writeback list|show|group|summarize` for raw and clustered signal
83
84
  - `fclt ai evolve list|show|review` for proposal state without applying changes
84
85
  - `fclt templates init automation learning-review` for recurring capture/review
@@ -86,9 +87,12 @@ Review surfaces:
86
87
  - `fclt templates init automation tool-call-audit` for repeated tool-friction review
87
88
 
88
89
  Evolution proposal metadata, markdown drafts, patch artifacts, writeback queues,
89
- and journals are runtime state. `fclt` stores them in machine-local Facult state;
90
- canonical assets in `~/.ai` or `<repo>/.ai` should only change when a proposal is
91
- applied.
90
+ and journals are runtime state. `fclt` stores JSON queues, proposal records,
91
+ draft refs, patches, and journals in machine-local Facult state. It mirrors
92
+ human-readable review artifacts into global `~/.ai/writebacks/...` and
93
+ `~/.ai/evolution/...`, including project-scoped artifacts under
94
+ `projects/<slug-hash>/` with cwd/project metadata in frontmatter. Canonical
95
+ assets in `~/.ai` or `<repo>/.ai` should only change when a proposal is applied.
92
96
 
93
97
  ## Default Agent Behavior
94
98
 
@@ -28,10 +28,18 @@ Use:
28
28
  fclt ai writeback add --kind <kind> --summary "<summary>" --asset <asset-selector>
29
29
  ```
30
30
 
31
- The writeback queue is runtime state, not canonical source. `fclt` stores it in
32
- machine-local Facult state so sandboxed agents can record durable friction
33
- without mutating `~/.ai` or a repo-local `.ai` unless an evolution proposal is
34
- later reviewed and applied.
31
+ The writeback queue is runtime state, not canonical source. `fclt` stores JSON
32
+ queue state in machine-local Facult state so sandboxed agents can record durable
33
+ friction without mutating canonical assets unless an evolution proposal is later
34
+ reviewed and applied.
35
+
36
+ Every writeback also refreshes a Markdown review artifact under the global
37
+ `~/.ai/writebacks/...` tree. Global signal lands in `~/.ai/writebacks/global/`;
38
+ project-scoped signal lands in `~/.ai/writebacks/projects/<slug-hash>/` with
39
+ frontmatter for scope, project root, cwd, target asset, status, tags, evidence,
40
+ and timestamps. Do not write writeback review artifacts into a repo-local `.ai`;
41
+ repo-local state should contribute project metadata and evidence, not bundled
42
+ private review files.
35
43
 
36
44
  Project-scoped writebacks should usually be recorded from the repo that produced
37
45
  the evidence. Global writebacks should be reserved for shared doctrine, shared
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "facult",
3
- "version": "2.8.12",
3
+ "version": "2.10.0",
4
4
  "description": "Manage canonical AI capabilities, sync surfaces, and evolution state.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/ai-state.ts CHANGED
@@ -58,15 +58,7 @@ async function newestPathMtime(path: string): Promise<number> {
58
58
  }
59
59
 
60
60
  async function watchedPathMtime(path: string): Promise<number> {
61
- const newest = await newestPathMtime(path);
62
- if (newest > 0) {
63
- return newest;
64
- }
65
- try {
66
- return (await stat(dirname(path))).mtimeMs;
67
- } catch {
68
- return 0;
69
- }
61
+ return await newestPathMtime(path);
70
62
  }
71
63
 
72
64
  async function canonicalAssetsNewerThanIndex(args: {
package/src/ai.ts CHANGED
@@ -7,10 +7,12 @@ import type { AssetScope, GraphNodeKind } from "./graph";
7
7
  import { loadGraph, resolveGraphNode } from "./graph-query";
8
8
  import {
9
9
  facultAiDraftDir,
10
+ facultAiEvolutionReviewDir,
10
11
  facultAiJournalPath,
11
12
  facultAiProposalDir,
12
13
  facultAiStateDir,
13
14
  facultAiWritebackQueuePath,
15
+ facultAiWritebackReviewDir,
14
16
  facultRootDir,
15
17
  legacyFacultAiStateDirs,
16
18
  projectRootFromAiRoot,
@@ -284,6 +286,176 @@ function uniqueStrings(values: string[]): string[] {
284
286
  return [...new Set(values.filter(Boolean))];
285
287
  }
286
288
 
289
+ function yamlScalar(value: unknown): string {
290
+ if (typeof value === "string") {
291
+ return JSON.stringify(value);
292
+ }
293
+ if (typeof value === "number" || typeof value === "boolean") {
294
+ return String(value);
295
+ }
296
+ if (Array.isArray(value)) {
297
+ return JSON.stringify(value);
298
+ }
299
+ if (value && typeof value === "object") {
300
+ return JSON.stringify(value);
301
+ }
302
+ return "null";
303
+ }
304
+
305
+ function renderFrontmatter(values: Record<string, unknown>): string {
306
+ const lines = Object.entries(values)
307
+ .filter(([, value]) => value !== undefined)
308
+ .map(([key, value]) => `${key}: ${yamlScalar(value)}`);
309
+ return ["---", ...lines, "---"].join("\n");
310
+ }
311
+
312
+ function markdownList(values: string[]): string[] {
313
+ return values.length > 0 ? values.map((value) => `- ${value}`) : ["- none"];
314
+ }
315
+
316
+ function renderEvidenceList(evidence: WritebackEvidence[]): string[] {
317
+ return evidence.length > 0
318
+ ? evidence.map((entry) => `- ${entry.type}: ${entry.ref}`)
319
+ : ["- none"];
320
+ }
321
+
322
+ function writebackReviewPath(
323
+ homeDir: string,
324
+ rootDir: string,
325
+ id: string
326
+ ): string {
327
+ return join(facultAiWritebackReviewDir(homeDir, rootDir), `${id}.md`);
328
+ }
329
+
330
+ function proposalReviewPath(
331
+ homeDir: string,
332
+ rootDir: string,
333
+ id: string
334
+ ): string {
335
+ return join(facultAiEvolutionReviewDir(homeDir, rootDir), `${id}.md`);
336
+ }
337
+
338
+ async function writeWritebackReviewArtifact(args: {
339
+ homeDir: string;
340
+ rootDir: string;
341
+ record: AiWritebackRecord;
342
+ }): Promise<void> {
343
+ const pathValue = writebackReviewPath(
344
+ args.homeDir,
345
+ args.rootDir,
346
+ args.record.id
347
+ );
348
+ await ensureParentDir(pathValue);
349
+ const body = [
350
+ renderFrontmatter({
351
+ id: args.record.id,
352
+ artifact: "writeback",
353
+ status: args.record.status,
354
+ scope: args.record.scope,
355
+ kind: args.record.kind,
356
+ confidence: args.record.confidence,
357
+ source: args.record.source,
358
+ assetRef: args.record.assetRef,
359
+ assetId: args.record.assetId,
360
+ assetType: args.record.assetType,
361
+ suggestedDestination: args.record.suggestedDestination,
362
+ domain: args.record.domain,
363
+ tags: args.record.tags,
364
+ projectSlug: args.record.projectSlug,
365
+ projectRoot: args.record.projectRoot,
366
+ cwd: args.record.projectRoot,
367
+ rootDir: args.rootDir,
368
+ createdAt: args.record.ts,
369
+ updatedAt: args.record.updatedAt ?? args.record.ts,
370
+ }),
371
+ "",
372
+ `# ${args.record.id}: ${args.record.summary}`,
373
+ "",
374
+ "## Summary",
375
+ args.record.summary,
376
+ "",
377
+ "## Evidence",
378
+ ...renderEvidenceList(args.record.evidence),
379
+ "",
380
+ "## Target",
381
+ `- asset: ${args.record.assetRef ?? "unassigned"}`,
382
+ `- destination: ${args.record.suggestedDestination ?? "unassigned"}`,
383
+ "",
384
+ ].join("\n");
385
+ await Bun.write(pathValue, `${body.trimEnd()}\n`);
386
+ }
387
+
388
+ async function writeProposalReviewArtifact(args: {
389
+ homeDir: string;
390
+ rootDir: string;
391
+ proposal: AiProposalRecord;
392
+ writebacks?: AiWritebackRecord[];
393
+ draftBody?: string | null;
394
+ }): Promise<void> {
395
+ const pathValue = proposalReviewPath(
396
+ args.homeDir,
397
+ args.rootDir,
398
+ args.proposal.id
399
+ );
400
+ await ensureParentDir(pathValue);
401
+ const body = [
402
+ renderFrontmatter({
403
+ id: args.proposal.id,
404
+ artifact: "evolution_proposal",
405
+ status: args.proposal.status,
406
+ scope: args.proposal.scope,
407
+ kind: args.proposal.kind,
408
+ confidence: args.proposal.confidence,
409
+ policyClass: args.proposal.policyClass,
410
+ reviewRequired: args.proposal.reviewRequired,
411
+ targets: args.proposal.targets,
412
+ sourceWritebacks: args.proposal.sourceWritebacks,
413
+ sourceProposals: args.proposal.sourceProposals,
414
+ draftRefs: args.proposal.draftRefs,
415
+ projectSlug: args.proposal.projectSlug,
416
+ projectRoot: args.proposal.projectRoot,
417
+ cwd: args.proposal.projectRoot,
418
+ rootDir: args.rootDir,
419
+ createdAt: args.proposal.ts,
420
+ updatedAt:
421
+ args.proposal.review?.reviewedAt ??
422
+ args.proposal.applyResult?.appliedAt ??
423
+ args.proposal.draftHistory?.at(-1)?.ts ??
424
+ args.proposal.ts,
425
+ }),
426
+ "",
427
+ `# ${args.proposal.id}: ${args.proposal.summary}`,
428
+ "",
429
+ "## Rationale",
430
+ args.proposal.rationale,
431
+ "",
432
+ "## Targets",
433
+ ...markdownList(args.proposal.targets),
434
+ "",
435
+ "## Source Writebacks",
436
+ ...(args.writebacks && args.writebacks.length > 0
437
+ ? args.writebacks.map(
438
+ (entry) => `- ${entry.id} (${entry.kind}): ${entry.summary}`
439
+ )
440
+ : markdownList(args.proposal.sourceWritebacks)),
441
+ "",
442
+ "## Draft Refs",
443
+ ...markdownList(args.proposal.draftRefs),
444
+ "",
445
+ ...(args.draftBody
446
+ ? [
447
+ "## Current Draft",
448
+ "",
449
+ "```markdown",
450
+ args.draftBody.trimEnd(),
451
+ "```",
452
+ "",
453
+ ]
454
+ : []),
455
+ ].join("\n");
456
+ await Bun.write(pathValue, `${body.trimEnd()}\n`);
457
+ }
458
+
287
459
  function slugToTitle(value: string): string {
288
460
  return value
289
461
  .split(SLUG_SPLIT_RE)
@@ -498,6 +670,11 @@ export async function addWriteback(
498
670
  evidence: record.evidence,
499
671
  tags: record.tags,
500
672
  });
673
+ await writeWritebackReviewArtifact({
674
+ homeDir,
675
+ rootDir: args.rootDir,
676
+ record,
677
+ });
501
678
  return record;
502
679
  }
503
680
 
@@ -556,6 +733,11 @@ async function updateWritebackStatus(
556
733
  refs: next.assetRef ? [next.assetRef] : undefined,
557
734
  tags: next.tags,
558
735
  });
736
+ await writeWritebackReviewArtifact({
737
+ homeDir,
738
+ rootDir: args.rootDir,
739
+ record: next,
740
+ });
559
741
  return next;
560
742
  }
561
743
 
@@ -743,6 +925,7 @@ async function writeProposalFile(
743
925
  join(dir, `${proposal.id}.json`),
744
926
  `${JSON.stringify(proposal, null, 2)}\n`
745
927
  );
928
+ await writeProposalReviewArtifact({ homeDir, rootDir, proposal });
746
929
  }
747
930
 
748
931
  export async function proposeEvolution(args: {
@@ -835,6 +1018,12 @@ export async function proposeEvolution(args: {
835
1018
  draftRefs: [],
836
1019
  };
837
1020
  await writeProposalFile(homeDir, args.rootDir, proposal);
1021
+ await writeProposalReviewArtifact({
1022
+ homeDir,
1023
+ rootDir: args.rootDir,
1024
+ proposal,
1025
+ writebacks: entries,
1026
+ });
838
1027
  await appendEvent(homeDir, args.rootDir, {
839
1028
  id: nextId("EVT", []),
840
1029
  ts: proposal.ts,
@@ -1203,6 +1392,13 @@ export async function draftProposal(
1203
1392
  }),
1204
1393
  })
1205
1394
  );
1395
+ await writeProposalReviewArtifact({
1396
+ homeDir,
1397
+ rootDir: args.rootDir,
1398
+ proposal: next,
1399
+ writebacks,
1400
+ draftBody,
1401
+ });
1206
1402
  await appendEvent(homeDir, args.rootDir, {
1207
1403
  id: "",
1208
1404
  ts: nowIso(),
@@ -1490,6 +1686,12 @@ export async function promoteProposal(
1490
1686
  applyResult: undefined,
1491
1687
  };
1492
1688
  await writeProposalFile(homeDir, targetRoot, promoted);
1689
+ await writeProposalReviewArtifact({
1690
+ homeDir,
1691
+ rootDir: targetRoot,
1692
+ proposal: promoted,
1693
+ writebacks: sourceWritebacks,
1694
+ });
1493
1695
  await appendEvent(homeDir, targetRoot, {
1494
1696
  id: "",
1495
1697
  ts: promoted.ts,
@@ -1,5 +1,5 @@
1
1
  // Generated by scripts/generate-builtin-assets.ts. Do not edit by hand.
2
2
 
3
3
  export const BUILTIN_OPERATING_MODEL_FILES = JSON.parse(
4
- '{"AGENTS.global.md":"# Facult Operating Defaults\\n\\nThis machine has a default Facult operating-model layer available.\\n\\nWhen work produces durable friction, weak verification, stale guidance, or a missing skill/tool capability, preserve that signal with `fclt ai writeback ...` when the target and scope are clear. When repeated writebacks or clearly missing capability point at a concrete improvement, use `fclt ai evolve ...` or the `capability-evolution` skill to make a reviewable proposal.\\n\\nFor writeback and evolution, read `@builtin/facult-operating-model/instructions/EVOLUTION.md`.\\nFor learning and writeback defaults, read `@builtin/facult-operating-model/instructions/LEARNING_AND_WRITEBACK.md`.\\nFor deciding whether capability belongs in global or project scope, read `@builtin/facult-operating-model/instructions/PROJECT_CAPABILITY.md`.\\nFor project operating-layer design, read `@builtin/facult-operating-model/instructions/INTEGRATION.md`.\\n\\nBuiltin specialist agents are available for:\\n- writeback curation\\n- evolution planning\\n- scope promotion\\n- integration auditing\\n\\nBuiltin skills are available for:\\n- capability evolution\\n- project operating-layer design\\n","agents/evolution-planner/agent.toml":"name = \\"evolution-planner\\"\\ndescription = \\"Turn repeated writeback into concrete capability proposals.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou plan capability evolution.\\n\\nPrioritize:\\n- smallest useful change\\n- correct target asset type\\n- correct target scope\\n- evidence that justifies the change\\n- repeated writeback clusters or clearly missing capabilities, not isolated preferences\\n\\nProposal kinds you should consider first:\\n- update_asset\\n- create_asset\\n- extract_snippet\\n- add_skill\\n- promote_asset\\n\\nDefault to project scope when the pattern is repo-local.\\nPromote to global only when reuse is demonstrated and pollution risk is low.\\n\\nReturn concise proposals ordered by expected leverage, including:\\n- proposal kind\\n- target asset\\n- target scope\\n- why this is the smallest durable change\\n\\nDo not escalate to evolution when a single writeback is enough.\\nDo not use evolution as a substitute for executable task tracking when the main need is owner, priority, state, or implementation follow-through.\\n\\"\\"\\"\\n","agents/integration-auditor/agent.toml":"name = \\"integration-auditor\\"\\ndescription = \\"Find where local success can still fail system-wide.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou audit integration risk.\\n\\nPrioritize:\\n- hidden dependencies\\n- rollout hazards\\n- operational constraints\\n- gaps between local verification and real system behavior\\n\\nReturn concise findings ordered by impact.\\n\\"\\"\\"\\n","agents/scope-promoter/agent.toml":"name = \\"scope-promoter\\"\\ndescription = \\"Decide whether learning belongs at project or global scope.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou decide scope.\\n\\nPrioritize:\\n- project specificity\\n- cross-project reuse potential\\n- pollution risk from globalizing too early\\n\\nWhen recommending promotion, make the standard path explicit:\\n- keep the source capability in project scope until promotion is approved\\n- create a reviewable global proposal\\n- do not treat promotion as implicit apply\\n\\nReturn concise decisions with rationale.\\n\\"\\"\\"\\n","agents/writeback-curator/agent.toml":"name = \\"writeback-curator\\"\\ndescription = \\"Turn noisy outcomes into high-signal writeback.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou curate durable writeback.\\n\\nPrioritize:\\n- repeated failures\\n- repeated wins\\n- stale guidance\\n- missing capability edges\\n- tool, skill, MCP, plugin, automation, or instruction friction that repeatedly slows work down\\n\\nFor each recommendation, prefer returning:\\n- suggested writeback kind\\n- best target asset or destination\\n- best scope (`project` or `global`)\\n- the evidence that justifies recording it\\n\\nDo not emit low-signal noise.\\nIf the learning is repo-specific, keep it project-scoped by default.\\nWhen the signal is already strong and the target is clear, prefer recommending direct writeback capture rather than abstract advice.\\nWhen the issue is executable tooling work, recommend task tracking for the fix and writeback only for the reusable operating-model learning.\\n\\"\\"\\"\\n","instructions/EVOLUTION.md":"---\\ndescription: Turn repeated signal into concrete capability changes.\\ntags: [facult, evolution, writeback]\\n---\\n\\n# Evolution\\n\\nUse writeback and evolution to improve the AI operating layer itself.\\n\\nEvolution is the synthesis and change side of the feedback loop. It turns accumulated writebacks, repeated tool friction, stale canonical assets, or clearly missing capability into small reviewable changes to instructions, skills, snippets, agents, or other markdown canonical assets.\\n\\n## When To Record Writeback\\n\\nRecord writeback when one of these is true:\\n\\n- the same failure repeats\\n- the same success pattern repeats\\n- guidance is stale or missing\\n- a prompt or loop has to be restated often\\n- a project-specific pattern looks reusable\\n\\nDo not record low-signal noise:\\n\\n- one-off annoyance with no reuse value\\n- generic \\"could be better\\" commentary\\n- duplicate observations with no new evidence\\n\\nThe intended default is that agents record strong writebacks themselves when the signal is clear enough, rather than only recommending that a user do it manually later.\\n\\nDo not wait for a weekly review to preserve high-signal evidence. Do wait for repeated evidence or a clearly missing capability before drafting a proposal.\\n\\n## Scope\\n\\nChoose `project` scope when the learning depends on:\\n\\n- repo architecture\\n- team workflow\\n- project tooling\\n- local testing or verification behavior\\n\\nChoose `global` scope when the learning is reusable across projects.\\n\\nPromote from project to global only after repeated reuse or strong evidence.\\n\\n## Writeback Kinds\\n\\nCommon kinds:\\n\\n- `weak_verification`\\n- `false_positive`\\n- `missing_context`\\n- `reusable_pattern`\\n- `capability_gap`\\n- `bad_default`\\n\\nEvery good writeback should try to include:\\n\\n- a concrete summary\\n- the best target asset if known\\n- the right scope\\n- domain or tags when useful\\n\\n## Operator Flow\\n\\nTypical workflow:\\n\\n```bash\\nfclt ai writeback add --kind weak_verification --summary \\"Checks were too shallow\\" --asset instruction:VERIFICATION\\nfclt ai writeback group --by asset\\nfclt ai writeback summarize --by domain\\nfclt ai evolve propose\\nfclt ai evolve draft EV-00001\\nfclt ai evolve accept EV-00001\\nfclt ai evolve apply EV-00001\\n```\\n\\nUse `fclt ai evolve draft <id> --append \\"...\\"` to revise a draft while preserving draft history.\\n\\nReview surfaces:\\n\\n- `fclt status --json` for queue/proposal paths, counts, and active scope\\n- `fclt ai writeback list|show|group|summarize` for raw and clustered signal\\n- `fclt ai evolve list|show|review` for proposal state without applying changes\\n- `fclt templates init automation learning-review` for recurring capture/review\\n- `fclt templates init automation evolution-review` for recurring proposal review\\n- `fclt templates init automation tool-call-audit` for repeated tool-friction review\\n\\nEvolution proposal metadata, markdown drafts, patch artifacts, writeback queues,\\nand journals are runtime state. `fclt` stores them in machine-local Facult state;\\ncanonical assets in `~/.ai` or `<repo>/.ai` should only change when a proposal is\\napplied.\\n\\n## Default Agent Behavior\\n\\nUse the smallest action that fits the signal:\\n\\n1. record one strong writeback when there is a clear durable learning\\n2. use `writeback-curator` when the target, kind, or scope is ambiguous\\n3. use `capability-evolution` or `evolution-planner` when repeated signal should become a proposal\\n4. do not draft or apply proposals just because a writeback exists; require repeated evidence or a clearly missing capability\\n\\nAvoid creating writeback/evolution noise for one-off nits, vague preferences, or speculative ideas without evidence.\\n\\nWhen the friction is executable product/tooling work that needs ownership,\\npriority, state, or implementation follow-through, create or update a real task\\nsystem item instead of forcing it into capability evolution. Use evolution for\\nthe reusable operating-layer change.\\n\\n## Proposal Kinds\\n\\nCurrent supported proposal kinds:\\n\\n- `update_asset`\\n- `create_asset`\\n- `extract_snippet`\\n- `add_skill`\\n- `promote_asset`\\n\\nUse the smallest durable change that fits the evidence.\\n\\n## Review And Apply Rules\\n\\n- draft before apply\\n- accept before apply\\n- prefer the smallest safe change\\n- keep reviewable evidence tied to source writebacks\\n- do not globalize project behavior too early\\n- do not apply high-risk global instruction, skill, plugin, or non-COS changes without explicit review/approval\\n\\nApply is for markdown canonical assets only. If the target is wrong, revise the proposal rather than forcing it through.\\n","instructions/INTEGRATION.md":"---\\ndescription: Detect where local success can still fail at integration boundaries.\\ntags: [facult, integration, verification]\\n---\\n\\n# Integration\\n\\nDistinguish local correctness from system correctness. Check hidden dependencies, rollout order, and operational constraints before calling work done.\\n","instructions/LEARNING_AND_WRITEBACK.md":"---\\ndescription: Preserve durable signal and record writeback when the operating layer should learn.\\ntags: [facult, learning, writeback]\\n---\\n\\n# Learning And Writeback\\n\\nUse this when work produces a durable decision, failure, success pattern, or missing guardrail that should outlive the current task.\\n\\nThis is the capture side of the feedback loop. The goal is to let normal agent work produce reusable signal without requiring a human to manually restate every friction point later.\\n\\n## Default Behavior\\n\\nThe normal path should be agent-driven.\\n\\nIf you can clearly answer:\\n\\n- what was learned\\n- why it matters\\n- where it should land\\n- whether it belongs in `project` or `global`\\n\\nthen record the writeback instead of only suggesting that someone should do it later.\\n\\nUse:\\n\\n```bash\\nfclt ai writeback add --kind <kind> --summary \\"<summary>\\" --asset <asset-selector>\\n```\\n\\nThe writeback queue is runtime state, not canonical source. `fclt` stores it in\\nmachine-local Facult state so sandboxed agents can record durable friction\\nwithout mutating `~/.ai` or a repo-local `.ai` unless an evolution proposal is\\nlater reviewed and applied.\\n\\nProject-scoped writebacks should usually be recorded from the repo that produced\\nthe evidence. Global writebacks should be reserved for shared doctrine, shared\\nskills, shared agents, tool behavior, or cross-project capability gaps.\\n\\n## Record Writeback When\\n\\n- the same failure or weak loop appears again\\n- a reusable success pattern shows up\\n- guidance is clearly stale or missing\\n- a repo-local behavior probably belongs in project capability\\n- a cross-project behavior probably belongs in global capability\\n- a skill, tool, MCP, plugin, automation, or instruction gap repeatedly slows work down\\n- an agent has to restate the same workaround, verification rule, or review rule\\n\\n## Do Not Record Writeback For\\n\\n- one-off annoyance with no durable value\\n- weak commentary with no target\\n- speculative ideas without evidence\\n- duplicate noise with no new signal\\n\\n## Follow Through\\n\\n- prefer one strong writeback over many weak ones\\n- mention the writeback id when summarizing what changed\\n- escalate to `capability-evolution` or `fclt ai evolve ...` only when the signal is repeated or clearly points at a durable capability change\\n- use `fclt ai writeback group --by asset` or `fclt ai writeback summarize --by domain` to review accumulated signal before proposing broad changes\\n- use scheduled `learning-review`, `evolution-review`, or `tool-call-audit` automations when the signal should be reviewed in the background\\n","instructions/PROJECT_CAPABILITY.md":"---\\ndescription: Decide what belongs in repo-local .ai versus the global store.\\ntags: [facult, project, scope]\\n---\\n\\n# Project Capability\\n\\nPrefer project scope when the guidance depends on repo architecture, team workflow, or colocated tooling. Promote to global only after repeated cross-project reuse.\\n\\n## Project First\\n\\nDefault to `<repo>/.ai` when the capability is about:\\n\\n- local architecture\\n- repo-specific testing or verification\\n- team conventions\\n- project tools and workflows\\n\\n## Promote Carefully\\n\\nPromote to `~/.ai` only when:\\n\\n- the same pattern succeeds in more than one repo\\n- the capability is not coupled to local architecture\\n- the global version will not create noise for unrelated projects\\n\\nUse:\\n\\n```bash\\nfclt ai evolve promote EV-00001 --to global --project\\n```\\n\\nThat creates a new global proposal for review. It does not auto-apply the promotion.\\n","skills/capability-evolution/SKILL.md":"---\\ndescription: Convert repeated writeback into concrete fclt capability proposals.\\ntags: [facult, evolution, writeback]\\n---\\n\\n# capability-evolution\\n\\n## When To Use\\nUse this skill when the same missing guidance, weak loop, or recurring win appears often enough that the AI system itself should probably change.\\n\\nDo not wait for a human operator by default if the signal is already clear and the environment permits local AI runtime state to be updated.\\n\\nUse writeback first when the signal is useful but not yet repeated. Use evolution when accumulated writebacks, repeated tool friction, or a clearly missing capability point at a specific target asset or new capability.\\n\\n## Scope Decision\\n\\nChoose `project` when the behavior depends on repo-local architecture or workflow.\\n\\nChoose `global` when the behavior is broadly reusable.\\n\\nIf unsure, start at project scope and promote later with evidence.\\n\\n## Working Flow\\n\\n1. record the strongest writeback\\n2. group or summarize repeated signal\\n3. choose the smallest valid proposal kind\\n4. draft the proposal\\n5. accept only after the target and scope are correct\\n6. apply only when the markdown target is the intended canonical asset\\n\\nUse:\\n\\n```bash\\nfclt ai writeback add ...\\nfclt ai writeback group --by asset\\nfclt ai writeback summarize --by domain\\nfclt ai evolve propose\\nfclt ai evolve draft EV-00001\\nfclt ai evolve draft EV-00001 --append \\"tighten the rule with a concrete verification step\\"\\nfclt ai evolve accept EV-00001\\nfclt ai evolve apply EV-00001\\n```\\n\\nFor background review loops, use:\\n\\n```bash\\nfclt templates init automation learning-review\\nfclt templates init automation evolution-review\\nfclt templates init automation tool-call-audit\\n```\\n\\nIf there is not yet enough repeated signal for evolution, record the writeback and stop there.\\n\\n## Proposal Kind Selection\\n\\n- `update_asset` for tightening existing guidance\\n- `create_asset` for missing instructions or docs\\n- `extract_snippet` for reusable partial guidance\\n- `add_skill` for reusable workflow instruction\\n- `promote_asset` for project-to-global promotion\\n\\nUse task tracking instead of evolution when the main work is an executable tool or product fix that needs an owner, priority, state, or delivery plan. Use evolution for the reusable instruction, skill, or operating-model change that should survive that fix.\\n\\n## Output Contract\\n- repeated signal\\n- proposed asset change\\n- target scope\\n- evidence\\n- smallest useful next step\\n","skills/project-operating-layer-design/SKILL.md":"---\\ndescription: Design or improve a repo-local .ai operating layer.\\ntags: [facult, project, design]\\n---\\n\\n# project-operating-layer-design\\n\\n## When To Use\\nUse this skill when a project needs its own `.ai/` structure, repo-specific instructions, or local bootstrap guidance.\\n\\n## Output Contract\\n- recommended `.ai/` layout\\n- what stays project-local\\n- what stays global\\n- what should remain generated runtime output only\\n"}'
4
+ '{"AGENTS.global.md":"# Facult Operating Defaults\\n\\nThis machine has a default Facult operating-model layer available.\\n\\nWhen work produces durable friction, weak verification, stale guidance, or a missing skill/tool capability, preserve that signal with `fclt ai writeback ...` when the target and scope are clear. When repeated writebacks or clearly missing capability point at a concrete improvement, use `fclt ai evolve ...` or the `capability-evolution` skill to make a reviewable proposal.\\n\\nFor writeback and evolution, read `@builtin/facult-operating-model/instructions/EVOLUTION.md`.\\nFor learning and writeback defaults, read `@builtin/facult-operating-model/instructions/LEARNING_AND_WRITEBACK.md`.\\nFor deciding whether capability belongs in global or project scope, read `@builtin/facult-operating-model/instructions/PROJECT_CAPABILITY.md`.\\nFor project operating-layer design, read `@builtin/facult-operating-model/instructions/INTEGRATION.md`.\\n\\nBuiltin specialist agents are available for:\\n- writeback curation\\n- evolution planning\\n- scope promotion\\n- integration auditing\\n\\nBuiltin skills are available for:\\n- capability evolution\\n- project operating-layer design\\n","agents/evolution-planner/agent.toml":"name = \\"evolution-planner\\"\\ndescription = \\"Turn repeated writeback into concrete capability proposals.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou plan capability evolution.\\n\\nPrioritize:\\n- smallest useful change\\n- correct target asset type\\n- correct target scope\\n- evidence that justifies the change\\n- repeated writeback clusters or clearly missing capabilities, not isolated preferences\\n\\nProposal kinds you should consider first:\\n- update_asset\\n- create_asset\\n- extract_snippet\\n- add_skill\\n- promote_asset\\n\\nDefault to project scope when the pattern is repo-local.\\nPromote to global only when reuse is demonstrated and pollution risk is low.\\n\\nReturn concise proposals ordered by expected leverage, including:\\n- proposal kind\\n- target asset\\n- target scope\\n- why this is the smallest durable change\\n\\nDo not escalate to evolution when a single writeback is enough.\\nDo not use evolution as a substitute for executable task tracking when the main need is owner, priority, state, or implementation follow-through.\\n\\"\\"\\"\\n","agents/integration-auditor/agent.toml":"name = \\"integration-auditor\\"\\ndescription = \\"Find where local success can still fail system-wide.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou audit integration risk.\\n\\nPrioritize:\\n- hidden dependencies\\n- rollout hazards\\n- operational constraints\\n- gaps between local verification and real system behavior\\n\\nReturn concise findings ordered by impact.\\n\\"\\"\\"\\n","agents/scope-promoter/agent.toml":"name = \\"scope-promoter\\"\\ndescription = \\"Decide whether learning belongs at project or global scope.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou decide scope.\\n\\nPrioritize:\\n- project specificity\\n- cross-project reuse potential\\n- pollution risk from globalizing too early\\n\\nWhen recommending promotion, make the standard path explicit:\\n- keep the source capability in project scope until promotion is approved\\n- create a reviewable global proposal\\n- do not treat promotion as implicit apply\\n\\nReturn concise decisions with rationale.\\n\\"\\"\\"\\n","agents/writeback-curator/agent.toml":"name = \\"writeback-curator\\"\\ndescription = \\"Turn noisy outcomes into high-signal writeback.\\"\\n\\ndeveloper_instructions = \\"\\"\\"\\nYou curate durable writeback.\\n\\nPrioritize:\\n- repeated failures\\n- repeated wins\\n- stale guidance\\n- missing capability edges\\n- tool, skill, MCP, plugin, automation, or instruction friction that repeatedly slows work down\\n\\nFor each recommendation, prefer returning:\\n- suggested writeback kind\\n- best target asset or destination\\n- best scope (`project` or `global`)\\n- the evidence that justifies recording it\\n\\nDo not emit low-signal noise.\\nIf the learning is repo-specific, keep it project-scoped by default.\\nWhen the signal is already strong and the target is clear, prefer recommending direct writeback capture rather than abstract advice.\\nWhen the issue is executable tooling work, recommend task tracking for the fix and writeback only for the reusable operating-model learning.\\n\\"\\"\\"\\n","instructions/EVOLUTION.md":"---\\ndescription: Turn repeated signal into concrete capability changes.\\ntags: [facult, evolution, writeback]\\n---\\n\\n# Evolution\\n\\nUse writeback and evolution to improve the AI operating layer itself.\\n\\nEvolution is the synthesis and change side of the feedback loop. It turns accumulated writebacks, repeated tool friction, stale canonical assets, or clearly missing capability into small reviewable changes to instructions, skills, snippets, agents, or other markdown canonical assets.\\n\\n## When To Record Writeback\\n\\nRecord writeback when one of these is true:\\n\\n- the same failure repeats\\n- the same success pattern repeats\\n- guidance is stale or missing\\n- a prompt or loop has to be restated often\\n- a project-specific pattern looks reusable\\n\\nDo not record low-signal noise:\\n\\n- one-off annoyance with no reuse value\\n- generic \\"could be better\\" commentary\\n- duplicate observations with no new evidence\\n\\nThe intended default is that agents record strong writebacks themselves when the signal is clear enough, rather than only recommending that a user do it manually later.\\n\\nDo not wait for a weekly review to preserve high-signal evidence. Do wait for repeated evidence or a clearly missing capability before drafting a proposal.\\n\\n## Scope\\n\\nChoose `project` scope when the learning depends on:\\n\\n- repo architecture\\n- team workflow\\n- project tooling\\n- local testing or verification behavior\\n\\nChoose `global` scope when the learning is reusable across projects.\\n\\nPromote from project to global only after repeated reuse or strong evidence.\\n\\n## Writeback Kinds\\n\\nCommon kinds:\\n\\n- `weak_verification`\\n- `false_positive`\\n- `missing_context`\\n- `reusable_pattern`\\n- `capability_gap`\\n- `bad_default`\\n\\nEvery good writeback should try to include:\\n\\n- a concrete summary\\n- the best target asset if known\\n- the right scope\\n- domain or tags when useful\\n\\n## Operator Flow\\n\\nTypical workflow:\\n\\n```bash\\nfclt ai writeback add --kind weak_verification --summary \\"Checks were too shallow\\" --asset instruction:VERIFICATION\\nfclt ai writeback group --by asset\\nfclt ai writeback summarize --by domain\\nfclt ai evolve propose\\nfclt ai evolve draft EV-00001\\nfclt ai evolve accept EV-00001\\nfclt ai evolve apply EV-00001\\n```\\n\\nUse `fclt ai evolve draft <id> --append \\"...\\"` to revise a draft while preserving draft history.\\n\\nReview surfaces:\\n\\n- open `~/.ai/writebacks/` and `~/.ai/evolution/` in a Markdown editor for frontmatter-rich global and project-scoped review artifacts\\n- `fclt status --json` for queue/proposal paths, review artifact paths, counts, and active scope\\n- `fclt ai writeback list|show|group|summarize` for raw and clustered signal\\n- `fclt ai evolve list|show|review` for proposal state without applying changes\\n- `fclt templates init automation learning-review` for recurring capture/review\\n- `fclt templates init automation evolution-review` for recurring proposal review\\n- `fclt templates init automation tool-call-audit` for repeated tool-friction review\\n\\nEvolution proposal metadata, markdown drafts, patch artifacts, writeback queues,\\nand journals are runtime state. `fclt` stores JSON queues, proposal records,\\ndraft refs, patches, and journals in machine-local Facult state. It mirrors\\nhuman-readable review artifacts into global `~/.ai/writebacks/...` and\\n`~/.ai/evolution/...`, including project-scoped artifacts under\\n`projects/<slug-hash>/` with cwd/project metadata in frontmatter. Canonical\\nassets in `~/.ai` or `<repo>/.ai` should only change when a proposal is applied.\\n\\n## Default Agent Behavior\\n\\nUse the smallest action that fits the signal:\\n\\n1. record one strong writeback when there is a clear durable learning\\n2. use `writeback-curator` when the target, kind, or scope is ambiguous\\n3. use `capability-evolution` or `evolution-planner` when repeated signal should become a proposal\\n4. do not draft or apply proposals just because a writeback exists; require repeated evidence or a clearly missing capability\\n\\nAvoid creating writeback/evolution noise for one-off nits, vague preferences, or speculative ideas without evidence.\\n\\nWhen the friction is executable product/tooling work that needs ownership,\\npriority, state, or implementation follow-through, create or update a real task\\nsystem item instead of forcing it into capability evolution. Use evolution for\\nthe reusable operating-layer change.\\n\\n## Proposal Kinds\\n\\nCurrent supported proposal kinds:\\n\\n- `update_asset`\\n- `create_asset`\\n- `extract_snippet`\\n- `add_skill`\\n- `promote_asset`\\n\\nUse the smallest durable change that fits the evidence.\\n\\n## Review And Apply Rules\\n\\n- draft before apply\\n- accept before apply\\n- prefer the smallest safe change\\n- keep reviewable evidence tied to source writebacks\\n- do not globalize project behavior too early\\n- do not apply high-risk global instruction, skill, plugin, or non-COS changes without explicit review/approval\\n\\nApply is for markdown canonical assets only. If the target is wrong, revise the proposal rather than forcing it through.\\n","instructions/INTEGRATION.md":"---\\ndescription: Detect where local success can still fail at integration boundaries.\\ntags: [facult, integration, verification]\\n---\\n\\n# Integration\\n\\nDistinguish local correctness from system correctness. Check hidden dependencies, rollout order, and operational constraints before calling work done.\\n","instructions/LEARNING_AND_WRITEBACK.md":"---\\ndescription: Preserve durable signal and record writeback when the operating layer should learn.\\ntags: [facult, learning, writeback]\\n---\\n\\n# Learning And Writeback\\n\\nUse this when work produces a durable decision, failure, success pattern, or missing guardrail that should outlive the current task.\\n\\nThis is the capture side of the feedback loop. The goal is to let normal agent work produce reusable signal without requiring a human to manually restate every friction point later.\\n\\n## Default Behavior\\n\\nThe normal path should be agent-driven.\\n\\nIf you can clearly answer:\\n\\n- what was learned\\n- why it matters\\n- where it should land\\n- whether it belongs in `project` or `global`\\n\\nthen record the writeback instead of only suggesting that someone should do it later.\\n\\nUse:\\n\\n```bash\\nfclt ai writeback add --kind <kind> --summary \\"<summary>\\" --asset <asset-selector>\\n```\\n\\nThe writeback queue is runtime state, not canonical source. `fclt` stores JSON\\nqueue state in machine-local Facult state so sandboxed agents can record durable\\nfriction without mutating canonical assets unless an evolution proposal is later\\nreviewed and applied.\\n\\nEvery writeback also refreshes a Markdown review artifact under the global\\n`~/.ai/writebacks/...` tree. Global signal lands in `~/.ai/writebacks/global/`;\\nproject-scoped signal lands in `~/.ai/writebacks/projects/<slug-hash>/` with\\nfrontmatter for scope, project root, cwd, target asset, status, tags, evidence,\\nand timestamps. Do not write writeback review artifacts into a repo-local `.ai`;\\nrepo-local state should contribute project metadata and evidence, not bundled\\nprivate review files.\\n\\nProject-scoped writebacks should usually be recorded from the repo that produced\\nthe evidence. Global writebacks should be reserved for shared doctrine, shared\\nskills, shared agents, tool behavior, or cross-project capability gaps.\\n\\n## Record Writeback When\\n\\n- the same failure or weak loop appears again\\n- a reusable success pattern shows up\\n- guidance is clearly stale or missing\\n- a repo-local behavior probably belongs in project capability\\n- a cross-project behavior probably belongs in global capability\\n- a skill, tool, MCP, plugin, automation, or instruction gap repeatedly slows work down\\n- an agent has to restate the same workaround, verification rule, or review rule\\n\\n## Do Not Record Writeback For\\n\\n- one-off annoyance with no durable value\\n- weak commentary with no target\\n- speculative ideas without evidence\\n- duplicate noise with no new signal\\n\\n## Follow Through\\n\\n- prefer one strong writeback over many weak ones\\n- mention the writeback id when summarizing what changed\\n- escalate to `capability-evolution` or `fclt ai evolve ...` only when the signal is repeated or clearly points at a durable capability change\\n- use `fclt ai writeback group --by asset` or `fclt ai writeback summarize --by domain` to review accumulated signal before proposing broad changes\\n- use scheduled `learning-review`, `evolution-review`, or `tool-call-audit` automations when the signal should be reviewed in the background\\n","instructions/PROJECT_CAPABILITY.md":"---\\ndescription: Decide what belongs in repo-local .ai versus the global store.\\ntags: [facult, project, scope]\\n---\\n\\n# Project Capability\\n\\nPrefer project scope when the guidance depends on repo architecture, team workflow, or colocated tooling. Promote to global only after repeated cross-project reuse.\\n\\n## Project First\\n\\nDefault to `<repo>/.ai` when the capability is about:\\n\\n- local architecture\\n- repo-specific testing or verification\\n- team conventions\\n- project tools and workflows\\n\\n## Promote Carefully\\n\\nPromote to `~/.ai` only when:\\n\\n- the same pattern succeeds in more than one repo\\n- the capability is not coupled to local architecture\\n- the global version will not create noise for unrelated projects\\n\\nUse:\\n\\n```bash\\nfclt ai evolve promote EV-00001 --to global --project\\n```\\n\\nThat creates a new global proposal for review. It does not auto-apply the promotion.\\n","skills/capability-evolution/SKILL.md":"---\\ndescription: Convert repeated writeback into concrete fclt capability proposals.\\ntags: [facult, evolution, writeback]\\n---\\n\\n# capability-evolution\\n\\n## When To Use\\nUse this skill when the same missing guidance, weak loop, or recurring win appears often enough that the AI system itself should probably change.\\n\\nDo not wait for a human operator by default if the signal is already clear and the environment permits local AI runtime state to be updated.\\n\\nUse writeback first when the signal is useful but not yet repeated. Use evolution when accumulated writebacks, repeated tool friction, or a clearly missing capability point at a specific target asset or new capability.\\n\\n## Scope Decision\\n\\nChoose `project` when the behavior depends on repo-local architecture or workflow.\\n\\nChoose `global` when the behavior is broadly reusable.\\n\\nIf unsure, start at project scope and promote later with evidence.\\n\\n## Working Flow\\n\\n1. record the strongest writeback\\n2. group or summarize repeated signal\\n3. choose the smallest valid proposal kind\\n4. draft the proposal\\n5. accept only after the target and scope are correct\\n6. apply only when the markdown target is the intended canonical asset\\n\\nUse:\\n\\n```bash\\nfclt ai writeback add ...\\nfclt ai writeback group --by asset\\nfclt ai writeback summarize --by domain\\nfclt ai evolve propose\\nfclt ai evolve draft EV-00001\\nfclt ai evolve draft EV-00001 --append \\"tighten the rule with a concrete verification step\\"\\nfclt ai evolve accept EV-00001\\nfclt ai evolve apply EV-00001\\n```\\n\\nFor background review loops, use:\\n\\n```bash\\nfclt templates init automation learning-review\\nfclt templates init automation evolution-review\\nfclt templates init automation tool-call-audit\\n```\\n\\nIf there is not yet enough repeated signal for evolution, record the writeback and stop there.\\n\\n## Proposal Kind Selection\\n\\n- `update_asset` for tightening existing guidance\\n- `create_asset` for missing instructions or docs\\n- `extract_snippet` for reusable partial guidance\\n- `add_skill` for reusable workflow instruction\\n- `promote_asset` for project-to-global promotion\\n\\nUse task tracking instead of evolution when the main work is an executable tool or product fix that needs an owner, priority, state, or delivery plan. Use evolution for the reusable instruction, skill, or operating-model change that should survive that fix.\\n\\n## Output Contract\\n- repeated signal\\n- proposed asset change\\n- target scope\\n- evidence\\n- smallest useful next step\\n","skills/project-operating-layer-design/SKILL.md":"---\\ndescription: Design or improve a repo-local .ai operating layer.\\ntags: [facult, project, design]\\n---\\n\\n# project-operating-layer-design\\n\\n## When To Use\\nUse this skill when a project needs its own `.ai/` structure, repo-specific instructions, or local bootstrap guidance.\\n\\n## Output Contract\\n- recommended `.ai/` layout\\n- what stays project-local\\n- what stays global\\n- what should remain generated runtime output only\\n"}'
5
5
  ) as Record<string, string>;
package/src/manage.ts CHANGED
@@ -137,6 +137,7 @@ export interface SyncOptions {
137
137
  tool?: string;
138
138
  dryRun?: boolean;
139
139
  builtinConflictMode?: "warn" | "overwrite";
140
+ adoptLive?: boolean;
140
141
  }
141
142
 
142
143
  const MANAGED_VERSION = 1 as const;
@@ -2421,12 +2422,14 @@ async function syncSkillSymlinks({
2421
2422
  rootDir,
2422
2423
  tool,
2423
2424
  dryRun,
2425
+ adoptLive,
2424
2426
  }: {
2425
2427
  homeDir: string;
2426
2428
  toolSkillsDir: string;
2427
2429
  rootDir: string;
2428
2430
  tool: string;
2429
2431
  dryRun?: boolean;
2432
+ adoptLive?: boolean;
2430
2433
  }): Promise<SkillSymlinkPlan> {
2431
2434
  const plan = await planSkillSymlinkChanges({
2432
2435
  homeDir,
@@ -2438,10 +2441,12 @@ async function syncSkillSymlinks({
2438
2441
  return plan;
2439
2442
  }
2440
2443
 
2441
- const adoptedConflicts = await adoptSkillSymlinkConflictsIntoCanonical({
2442
- rootDir,
2443
- conflicts: plan.conflicts,
2444
- });
2444
+ const adoptedConflicts = adoptLive
2445
+ ? await adoptSkillSymlinkConflictsIntoCanonical({
2446
+ rootDir,
2447
+ conflicts: plan.conflicts,
2448
+ })
2449
+ : [];
2445
2450
  const adoptedNames = new Set(
2446
2451
  adoptedConflicts.map((conflict) => conflict.name)
2447
2452
  );
@@ -3646,7 +3651,8 @@ function logRenderedConflicts(
3646
3651
  function logSkillSymlinkConflicts(
3647
3652
  tool: string,
3648
3653
  conflicts: SkillSymlinkConflict[],
3649
- dryRun?: boolean
3654
+ dryRun?: boolean,
3655
+ mode: "adopt" | "skip" = "skip"
3650
3656
  ) {
3651
3657
  for (const conflict of conflicts) {
3652
3658
  const verb =
@@ -3654,9 +3660,13 @@ function logSkillSymlinkConflicts(
3654
3660
  ? dryRun
3655
3661
  ? "would preserve"
3656
3662
  : "preserved"
3657
- : dryRun
3658
- ? "would adopt"
3659
- : "adopted";
3663
+ : mode === "adopt"
3664
+ ? dryRun
3665
+ ? "would adopt"
3666
+ : "adopted"
3667
+ : dryRun
3668
+ ? "would skip"
3669
+ : "skipped";
3660
3670
  const state =
3661
3671
  conflict.reason === "unmanaged"
3662
3672
  ? "it is not in canonical skill state"
@@ -3667,7 +3677,7 @@ function logSkillSymlinkConflicts(
3667
3677
  ? ` (canonical ${conflict.canonicalPath})`
3668
3678
  : "";
3669
3679
  console.warn(
3670
- `${tool}: ${verb} skill ${conflict.name} from ${conflict.livePath}${canonical} because ${state}.`
3680
+ `${tool}: ${verb} skill ${conflict.name} from ${conflict.livePath}${canonical} because ${state}.${mode === "skip" && conflict.reason !== "disabled" ? ' Rerun with "--adopt-live" to import it into canonical state.' : ""}`
3671
3681
  );
3672
3682
  }
3673
3683
  }
@@ -4470,6 +4480,7 @@ async function syncManagedToolEntry({
4470
4480
  rootDir,
4471
4481
  dryRun,
4472
4482
  builtinConflictMode,
4483
+ adoptLive,
4473
4484
  }: {
4474
4485
  homeDir: string;
4475
4486
  tool: string;
@@ -4477,6 +4488,7 @@ async function syncManagedToolEntry({
4477
4488
  rootDir: string;
4478
4489
  dryRun?: boolean;
4479
4490
  builtinConflictMode?: "warn" | "overwrite";
4491
+ adoptLive?: boolean;
4480
4492
  }) {
4481
4493
  const correlationId = randomUUID();
4482
4494
  const baseLedger = syncLedgerBase({
@@ -4515,14 +4527,15 @@ async function syncManagedToolEntry({
4515
4527
  automationDir: entry.automationDir,
4516
4528
  });
4517
4529
 
4518
- const adoptedSkills = dryRun
4519
- ? []
4520
- : await repairManagedCanonicalContent({
4521
- homeDir,
4522
- rootDir,
4523
- tool,
4524
- entry,
4525
- });
4530
+ const adoptedSkills =
4531
+ dryRun || !adoptLive
4532
+ ? []
4533
+ : await repairManagedCanonicalContent({
4534
+ homeDir,
4535
+ rootDir,
4536
+ tool,
4537
+ entry,
4538
+ });
4526
4539
 
4527
4540
  const skillPlan = entry.skillsDir
4528
4541
  ? await syncSkillSymlinks({
@@ -4531,6 +4544,7 @@ async function syncManagedToolEntry({
4531
4544
  rootDir,
4532
4545
  tool,
4533
4546
  dryRun,
4547
+ adoptLive,
4534
4548
  })
4535
4549
  : { add: [], remove: [], conflicts: [], adopted: [] };
4536
4550
  const skillLedgerEvents = collectSkillLedgerEvents({
@@ -4895,8 +4909,8 @@ async function syncManagedToolEntry({
4895
4909
  logRenderedConflicts(tool, configRendered.conflicts);
4896
4910
  logRenderedConflicts(tool, mcpRendered.conflicts);
4897
4911
  logRenderedConflicts(tool, pluginRendered.conflicts);
4898
- logSkillSymlinkConflicts(tool, skillPlan.adopted);
4899
- logSkillSymlinkConflicts(tool, skillPlan.conflicts);
4912
+ logSkillSymlinkConflicts(tool, skillPlan.adopted, false, "adopt");
4913
+ logSkillSymlinkConflicts(tool, skillPlan.conflicts, false, "skip");
4900
4914
 
4901
4915
  updateRenderedTargetState({
4902
4916
  entry,
@@ -5004,6 +5018,7 @@ export async function syncManagedTools(opts: SyncOptions = {}) {
5004
5018
  rootDir,
5005
5019
  dryRun: opts.dryRun,
5006
5020
  builtinConflictMode: opts.builtinConflictMode,
5021
+ adoptLive: opts.adoptLive,
5007
5022
  });
5008
5023
  }
5009
5024
 
@@ -5196,16 +5211,20 @@ export async function syncCommand(argv: string[]) {
5196
5211
  console.log(`fclt sync — sync managed tools with canonical state
5197
5212
 
5198
5213
  Usage:
5199
- fclt sync [tool] [--dry-run] [--builtin-conflicts overwrite] [--root PATH|--global|--project]
5214
+ fclt sync [tool] [--dry-run] [--adopt-live] [--builtin-conflicts overwrite] [--root PATH|--global|--project]
5200
5215
 
5201
5216
  Options:
5202
5217
  --dry-run Show what would change
5218
+ --adopt-live Import live tool content into canonical state before rendering
5203
5219
  --builtin-conflicts overwrite Replace locally modified builtin-backed rendered files
5204
5220
  `);
5205
5221
  return;
5206
5222
  }
5207
5223
  const tool = parsed.argv.find((arg) => !arg.startsWith("-"));
5208
5224
  const dryRun = parsed.argv.includes("--dry-run");
5225
+ const adoptLive =
5226
+ parsed.argv.includes("--adopt-live") ||
5227
+ parsed.argv.includes("--adopt-live-skills");
5209
5228
  const builtinConflictIndex = parsed.argv.indexOf("--builtin-conflicts");
5210
5229
  let builtinConflictMode: "warn" | "overwrite" | undefined;
5211
5230
  if (builtinConflictIndex !== -1) {
@@ -5221,6 +5240,7 @@ Options:
5221
5240
  await syncManagedTools({
5222
5241
  tool,
5223
5242
  dryRun,
5243
+ adoptLive,
5224
5244
  builtinConflictMode,
5225
5245
  rootDir: resolveCliContextRoot({
5226
5246
  rootArg: parsed.rootArg,
package/src/paths.ts CHANGED
@@ -238,7 +238,7 @@ export function facultStateDir(
238
238
  return join(resolvedRoot, ".facult");
239
239
  }
240
240
 
241
- function machineStateProjectKey(
241
+ export function machineStateProjectKey(
242
242
  rootDir: string,
243
243
  home: string = defaultHomeDir()
244
244
  ): string {
@@ -413,6 +413,37 @@ export function facultAiDraftDir(
413
413
  return join(facultAiRuntimeScopeDir(home, rootDir), "evolution", "drafts");
414
414
  }
415
415
 
416
+ export function facultAiReviewScopeDir(
417
+ artifactDir: "writebacks" | "evolution",
418
+ home: string = defaultHomeDir(),
419
+ rootDir?: string
420
+ ): string {
421
+ const resolvedRoot = rootDir ?? facultRootDir(home);
422
+ const projectRoot = projectRootFromAiRoot(resolvedRoot, home);
423
+ return projectRoot
424
+ ? join(
425
+ preferredGlobalAiRoot(home),
426
+ artifactDir,
427
+ "projects",
428
+ machineStateProjectKey(resolvedRoot, home)
429
+ )
430
+ : join(preferredGlobalAiRoot(home), artifactDir, "global");
431
+ }
432
+
433
+ export function facultAiWritebackReviewDir(
434
+ home: string = defaultHomeDir(),
435
+ rootDir?: string
436
+ ): string {
437
+ return facultAiReviewScopeDir("writebacks", home, rootDir);
438
+ }
439
+
440
+ export function facultAiEvolutionReviewDir(
441
+ home: string = defaultHomeDir(),
442
+ rootDir?: string
443
+ ): string {
444
+ return facultAiReviewScopeDir("evolution", home, rootDir);
445
+ }
446
+
416
447
  export function facultConfigPath(home: string = defaultHomeDir()): string {
417
448
  return join(preferredGlobalFacultStateDir(home), "config.json");
418
449
  }
package/src/remote.ts CHANGED
@@ -383,7 +383,7 @@ Use this memory for pattern continuity:
383
383
  - For wide reviews, partition evidence by cwd first; do not let one repo's evidence stand in for another.
384
384
  - Grounding: prefer evidence from session messages, tool calls, shell commands, diffs, tests, commits, and touched files.
385
385
  - Threshold: only encode signal when you can name what was learned, why it matters, and the most plausible destination.
386
- - Scope: default to project writeback only when the repo has a project-local \`.ai\` root. If a local writable repo is missing one, bootstrap baseline project AI state with \`fclt templates init project-ai\` before retrying project-scoped writeback. If bootstrap fails or the repo is not writable, treat that as the blocker instead of silently falling back to global runtime state.
386
+ - Scope: default to project writeback only when the repo has a project-local \`.ai\` root for capability context. If a local writable repo is missing one, bootstrap baseline project AI state with \`fclt templates init project-ai\` before retrying project-scoped writeback. Writeback/evolution review artifacts still belong under global \`~/.ai/writebacks/projects/...\` and \`~/.ai/evolution/projects/...\`, not inside the repo-local \`.ai\`. If bootstrap fails or the repo is not writable, treat that as the blocker instead of silently falling back to global runtime state.
387
387
  - Promote to global only when the same signal appears across multiple repos or clearly targets shared doctrine, shared agents, or shared skills.
388
388
  - Verification: distinguish one-off friction from a repeated pattern before escalating it.
389
389
  - If available, use [$feedback-loop-setup]({{feedbackLoopSkill}}) when the review needs stronger feedback loops or verification framing.
@@ -409,7 +409,7 @@ Grounding rules:
409
409
 
410
410
  Decision rules:
411
411
  - Use \`fclt ai writeback add\` when the signal, target asset, and scope are clear.
412
- - Before attempting project-scoped writeback, verify the cwd has a repo-local \`.ai\` root. If it does not and the cwd is a local writable repo, run \`fclt templates init project-ai\` from that repo root, then continue. If bootstrap fails or the repo is not writable, report the writeback as blocked by missing project AI state rather than falling back to merged/global runtime state.
412
+ - Before attempting project-scoped writeback, verify the cwd has a repo-local \`.ai\` root for capability context. If it does not and the cwd is a local writable repo, run \`fclt templates init project-ai\` from that repo root, then continue. Do not write writeback/evolution review artifacts into the repo-local \`.ai\`; fclt mirrors them under global \`~/.ai/writebacks/projects/...\` and \`~/.ai/evolution/projects/...\` with cwd/project metadata. If bootstrap fails or the repo is not writable, report the writeback as blocked by missing project AI state rather than falling back to merged/global runtime state.
413
413
  - Before passing \`--asset\`, verify the target resolves in the Facult graph. If the destination is a raw file path or otherwise not graph-backed, report that as a missing-asset blocker instead of retrying blind.
414
414
  - Use \`fclt ai evolve\` only when repeated signal is strong enough to justify a reviewable capability change.
415
415
  - Prefer project scope unless the learning clearly belongs in shared global doctrine, shared agents, shared skills, or other cross-project capability.
package/src/status.ts CHANGED
@@ -3,10 +3,12 @@ import { dirname, join } from "node:path";
3
3
  import { parseCliContextArgs, resolveCliContextRoot } from "./cli-context";
4
4
  import { loadManagedState } from "./manage";
5
5
  import {
6
+ facultAiEvolutionReviewDir,
6
7
  facultAiGraphPath,
7
8
  facultAiIndexPath,
8
9
  facultAiProposalDir,
9
10
  facultAiWritebackQueuePath,
11
+ facultAiWritebackReviewDir,
10
12
  facultMachineStateDir,
11
13
  facultRootDir,
12
14
  projectRootFromAiRoot,
@@ -41,8 +43,10 @@ export interface FacultStatus {
41
43
  };
42
44
  writeback: {
43
45
  queuePath: string;
46
+ reviewDir: string;
44
47
  pendingCount: number;
45
48
  proposalDir: string;
49
+ evolutionReviewDir: string;
46
50
  proposalCount: number;
47
51
  };
48
52
  issues: StatusIssue[];
@@ -175,6 +179,8 @@ export async function buildStatus(opts?: {
175
179
  const graphPath = facultAiGraphPath(homeDir, contextRoot);
176
180
  const queuePath = facultAiWritebackQueuePath(homeDir, contextRoot);
177
181
  const proposalDir = facultAiProposalDir(homeDir, contextRoot);
182
+ const reviewDir = facultAiWritebackReviewDir(homeDir, contextRoot);
183
+ const evolutionReviewDir = facultAiEvolutionReviewDir(homeDir, contextRoot);
178
184
  const managed = await loadManagedState(homeDir, contextRoot);
179
185
 
180
186
  const issues: StatusIssue[] = [];
@@ -222,8 +228,10 @@ export async function buildStatus(opts?: {
222
228
  },
223
229
  writeback: {
224
230
  queuePath,
231
+ reviewDir,
225
232
  pendingCount: await countPendingWritebacks(homeDir, contextRoot),
226
233
  proposalDir,
234
+ evolutionReviewDir,
227
235
  proposalCount: await countActiveProposals(homeDir, contextRoot),
228
236
  },
229
237
  issues,
@@ -247,6 +255,8 @@ function printStatus(status: FacultStatus) {
247
255
  console.log(
248
256
  `writeback: ${status.writeback.pendingCount} queued, ${status.writeback.proposalCount} proposals`
249
257
  );
258
+ console.log(`writeback review: ${status.writeback.reviewDir}`);
259
+ console.log(`evolution review: ${status.writeback.evolutionReviewDir}`);
250
260
  if (status.issues.length > 0) {
251
261
  console.log("issues:");
252
262
  for (const issue of status.issues) {