@ericrisco/rsc 0.1.12 → 0.1.14

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/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.12",
2
+ "version": "0.1.14",
3
3
  "counts": {
4
4
  "skills": 231
5
5
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ericrisco/rsc",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Eric Risco's agent-skills catalog as a granular, self-recommending CLI installer.",
5
5
  "type": "module",
6
6
  "bin": {
package/scripts/lib/ui.js CHANGED
@@ -57,13 +57,33 @@ function hsl(h, s = 1, l = 0.6) {
57
57
  }
58
58
 
59
59
  // One frame: rainbow per character, diagonal phase, revealed up to `cols`.
60
- function frame(phase, cols) {
60
+ const SPARK = ['✦', '✧', '⋆', '✺', '·', '*'];
61
+ const SPARK_C = ['\x1b[1;97m', '\x1b[1;93m', '\x1b[1;96m']; // bright white / yellow / cyan
62
+
63
+ // `n` random twinkles as a Map "r,c" -> pre-coloured glyph string.
64
+ function sparkles(n, rows, W) {
65
+ const m = new Map();
66
+ for (let i = 0; i < n; i++) {
67
+ const r = Math.floor(Math.random() * rows);
68
+ const c = Math.floor(Math.random() * W);
69
+ const g = SPARK[Math.floor(Math.random() * SPARK.length)];
70
+ m.set(`${r},${c}`, SPARK_C[Math.floor(Math.random() * SPARK_C.length)] + g);
71
+ }
72
+ return m;
73
+ }
74
+
75
+ // One frame: rainbow per character (or white), revealed up to `cols`, with
76
+ // sparkles overlaid on top wherever the map has a position.
77
+ function frame(phase, cols, sparks, white) {
61
78
  return ART.map((line, r) => {
62
79
  const chars = [...line];
63
80
  let out = '';
64
81
  for (let c = 0; c < chars.length && c < cols; c++) {
82
+ const sp = sparks && sparks.get(`${r},${c}`);
83
+ if (sp) { out += sp; continue; }
65
84
  const ch = chars[c];
66
85
  if (ch === ' ') { out += ' '; continue; }
86
+ if (white) { out += `\x1b[1;97m${ch}`; continue; }
67
87
  const [rr, gg, bb] = hsl((c * 5 + r * 14 + phase * 20) % 360);
68
88
  out += `\x1b[1;38;2;${rr};${gg};${bb}m${ch}`;
69
89
  }
@@ -83,27 +103,31 @@ export async function banner() {
83
103
  const W = Math.max(...ART.map((l) => [...l].length));
84
104
  stdout.write('\x1b[?25l'); // hide cursor
85
105
  say('');
86
- // 1) letters slide in left → right
106
+ // 1) letters slide in left → right, a sparkle riding the drawing edge
87
107
  let first = true;
88
108
  for (let cols = 2; cols <= W; cols += 2) {
89
109
  if (!first) stdout.write(`\x1b[${rows}A`);
90
110
  first = false;
91
- stdout.write(frame(0, cols));
111
+ const edge = new Map();
112
+ const er = Math.floor(Math.random() * rows);
113
+ edge.set(`${er},${Math.min(cols - 1, W - 1)}`, '\x1b[1;97m✦');
114
+ if (Math.random() < 0.5) edge.set(`${Math.floor(Math.random() * rows)},${Math.min(cols, W - 1)}`, '\x1b[1;93m·');
115
+ stdout.write(frame(0, cols, edge));
92
116
  await sleep(12);
93
117
  }
94
- // 2) flowing rainbow diagonal sweeps
118
+ // 2) flowing rainbow diagonal sweeps with twinkling sparkles
95
119
  for (let phase = 1; phase <= 30; phase++) {
96
120
  stdout.write(`\x1b[${rows}A`);
97
- stdout.write(frame(phase, W));
121
+ stdout.write(frame(phase, W, sparkles(4, rows, W)));
98
122
  await sleep(26);
99
123
  }
100
- // 3) double white flash — the pop
124
+ // 3) double white flash with a sparkle burst — the pop
101
125
  for (let f = 0; f < 2; f++) {
102
126
  stdout.write(`\x1b[${rows}A`);
103
- stdout.write(ART.map((l) => `\x1b[2K\x1b[1;97m${l}\x1b[0m`).join('\n') + '\n');
127
+ stdout.write(frame(0, W, sparkles(12, rows, W), true));
104
128
  await sleep(60);
105
129
  stdout.write(`\x1b[${rows}A`);
106
- stdout.write(frame(15, W));
130
+ stdout.write(frame(15, W, sparkles(3, rows, W)));
107
131
  await sleep(60);
108
132
  }
109
133
  // settle on a final rainbow snapshot
@@ -11,7 +11,7 @@ profiles: [minimal, core, full]
11
11
  The **harness** is the control plane of a workspace. A workspace need not be code: it can be a company, an ops desk, a legal archive, a personal knowledge vault. Whatever it is, the harness is the durable apparatus that keeps it operable and legible, made of three parts:
12
12
 
13
13
  - **`01-TOOLS/<PROVIDER>/`** — the operational tooling layer. One folder per external provider, co-locating credentials (`.env`) with the scripts that consume them. Each tool ships a working `test_connection` against the real API.
14
- - **`02-DOCS/`** — the **Karpathy chaos→knowledge engine**: a domain-agnostic LLM wiki (`inbox/` + `raw/` + `wiki/` + `wiki/index.md` + `wiki/log.md` + `wiki/gaps.md` + `wiki/scores.json`), fully embedded in this skill. The user drops **any raw file in any format** (PDF, image, CSV, JSON, txt, html…) into `inbox/`; an **Inbox Sweep** ("the agent goes for a walk") extracts, classifies by content, cross-links, and compiles it into the wiki — see `references/ingest-formats.md` for the multiformat Fetch and `references/wiki-protocol.md` for the protocol. Topics are inferred from content (`finanzas/`, `legal/`, `crm/`…), never hardcoded to software docs. The wiki **self-improves continuously**: every Ingest, Sweep and Query triggers a Maintenance Pass (deterministic lint, score recomputation, gap detection, See Also sweep), and every N interactions a Micro-Improve runs (rewrite 1 low-scoring article, fill 1 gap, preserving old versions in `_archive/`). Deep Improve runs on explicit request or via scheduled cron. No external skill needed.
14
+ - **`02-DOCS/`** — the **Karpathy chaos→knowledge engine**: a domain-agnostic LLM wiki (`inbox/` + `raw/` + `raw/worklog/` + `wiki/` + `wiki/index.md` + `wiki/log.md` + `wiki/gaps.md` + `wiki/scores.json` + the `.base` views), fully embedded in this skill. It feeds from **two on-ramps**: (1) the user drops **any raw file in any format** (PDF, image, CSV, JSON, txt, html…) into `inbox/`, and an **Inbox Sweep** ("the agent goes for a walk") extracts, classifies, cross-links, and compiles it; (2) a **Worklog Sweep** captures **what we do** — every meaningful session of work is itself a `raw` source (`raw/worklog/`) compiled into the wiki, fired by a `PreCompact`/`SessionEnd` hook, by an explicit milestone (a commit), or by the daily curation automation (`references/daily-curation-automation.md`). The wiki is **Obsidian-native**: wikilinks, YAML frontmatter (Properties), readable filenames, and `.base` views give a real graph + live tables structure, **not vector DB / embeddings / RAG**. The agent writes it; the human reads it in Obsidian. See `references/wiki-protocol.md` for the protocol, `references/ingest-formats.md` for the multiformat Fetch, `references/wiki-worklog-template.md` for the work capture, and `references/obsidian-scaffolding.md` for the vault scaffolding. Topics are inferred from content (`finanzas/`, `legal/`, `crm/`…), never hardcoded. The wiki **self-improves continuously**: every Ingest, Sweep and Query triggers a Maintenance Pass (deterministic lint, score recomputation, gap detection, Related/See-Also sweep), and every N interactions a Micro-Improve runs. Deep Improve runs on explicit request or via the scheduled daily curation. No external skill needed.
15
15
  - **The Knowledge map** — the `## Knowledge map` section of the root `CLAUDE.md` that indexes the wiki (including the `harness/` topic) and is read by every other skill before it works in its area.
16
16
 
17
17
  `harness` is the **protagonist concept**. `init` is the bootstrap front door — it gauges the user, drafts the profile, and hands off the first scaffold. THIS skill (`harness`) is the **ongoing control**: it audits, migrates, scaffolds, sweeps the inbox, and keeps the wiki, the tooling and the Knowledge map honest over the life of the workspace. It also generates root `CLAUDE.md` and `AGENTS.md`, and migrates legacy `XX-*` numbered folders into the canonical layout.
@@ -55,6 +55,8 @@ phase, last verdict, next steps, risks, commands and skill_resolution. This is
55
55
  not a replacement for the wiki; it is the recovery note that lets the next
56
56
  agent resume without trusting chat history.
57
57
 
58
+ **Opt-out marker.** When a workspace has no profile yet, a freshly-installed session auto-starts `init` (via the `suggest` Onboarding gate and claude's SessionStart hook). A `.rsc/.no-harness` file is the explicit opt-out: present → never auto-start onboarding in this repo, even without a profile. `harness` treats it as canonical and never overwrites or deletes it.
59
+
58
60
  ### 4. Decision pattern — "siempre 3 opciones"
59
61
 
60
62
  For **any significant decision** (deploy target, database, framework, hosting, tooling…):
@@ -98,12 +100,15 @@ harness/
98
100
  │ ├── agents-md-template.md ← root AGENTS.md template
99
101
  │ ├── tools-readme-template.md ← 01-TOOLS/README.md catalog template
100
102
  │ ├── audit-report-template.md ← exact format of the audit report shown to user
101
- │ ├── wiki-protocol.md ← embedded wiki protocol + Inbox Sweep + Continuous Improvement
103
+ │ ├── wiki-protocol.md ← embedded wiki protocol + Inbox/Worklog Sweep + Continuous Improvement
102
104
  │ ├── ingest-formats.md ← multiformat Fetch (PDF, image, CSV, JSON, html…)
103
105
  │ ├── inbox-readme-template.md ← the inbox/README.md drop-zone contract
104
106
  │ ├── wiki-raw-template.md ← format for raw/<topic>/*.md
105
- │ ├── wiki-article-template.md ← format for wiki/<topic>/*.md
106
- │ ├── wiki-index-template.md ← format for wiki/index.md (with Score column)
107
+ │ ├── wiki-worklog-template.md ← format for raw/worklog/*.md (work-driven capture)
108
+ │ ├── wiki-article-template.md ← format for wiki/<topic>/*.md (Obsidian frontmatter + wikilinks)
109
+ │ ├── wiki-index-template.md ← format for wiki/index.md (machine catalog; .base = human nav)
110
+ │ ├── obsidian-scaffolding.md ← .base views, .gitignore, attachments, .obsidian config
111
+ │ ├── daily-curation-automation.md ← portable scheduled compounding pass (the third trigger)
107
112
  │ ├── wiki-archive-template.md ← format for archived query answers
108
113
  │ └── wiki-gaps-template.md ← format for wiki/gaps.md (Knowledge Gaps log)
109
114
  ├── assets/
@@ -321,12 +326,15 @@ If any of these occur, stop and report:
321
326
  - `references/tools-readme-template.md` — `01-TOOLS/README.md` catalog template.
322
327
  - `references/audit-report-template.md` — text summary format for the in-conversation audit summary.
323
328
  - `references/audit-report-template.html` — HTML format for the full per-run audit artifact written to `02-DOCS/audits/`.
324
- - `references/wiki-protocol.md` — embedded protocol for the `02-DOCS/` chaos→knowledge layer (initialization, **Inbox Sweep**, ingest, query, lint, **Continuous Improvement**: Maintenance Pass, Micro-Improve, Deep Improve).
329
+ - `references/wiki-protocol.md` — embedded protocol for the `02-DOCS/` chaos→knowledge layer (initialization, **Inbox Sweep**, **Worklog Sweep**, ingest, query, lint, **Continuous Improvement**: Maintenance Pass, Micro-Improve, Deep Improve; Obsidian-native conventions).
325
330
  - `references/ingest-formats.md` — multiformat Fetch: how any input (PDF, image, CSV/Excel, JSON/API, html, docx, email, unknown binary) becomes `raw/` markdown with the original preserved in `_originals/`.
326
331
  - `references/inbox-readme-template.md` — the `inbox/README.md` drop-zone contract shown to the user.
327
332
  - `references/wiki-raw-template.md` — format for `02-DOCS/raw/<topic>/*.md`.
328
- - `references/wiki-article-template.md` — format for `02-DOCS/wiki/<topic>/*.md`.
329
- - `references/wiki-index-template.md` — format for `02-DOCS/wiki/index.md` (with Score column).
333
+ - `references/wiki-worklog-template.md` — format for `02-DOCS/raw/worklog/*.md` (the work-driven capture; the session as a raw source).
334
+ - `references/wiki-article-template.md` — format for `02-DOCS/wiki/<topic>/*.md` (Obsidian frontmatter + wikilinks + `## Related`).
335
+ - `references/wiki-index-template.md` — format for `02-DOCS/wiki/index.md` (machine catalog; the `.base` views are the human navigation).
336
+ - `references/obsidian-scaffolding.md` — the vault scaffolding: `.base` views, `.gitignore`, `attachments/`, `.obsidian` config (no vector DB / RAG).
337
+ - `references/daily-curation-automation.md` — portable scheduled compounding pass; on Claude Code wired via the `schedule` skill.
330
338
  - `references/wiki-archive-template.html` — HTML format for archived query answers (point-in-time, never edited).
331
339
  - `references/wiki-dashboard-template.html` — HTML format for the live wiki dashboard, regenerated by Maintenance Pass.
332
340
  - `references/wiki-deep-improve-report-template.html` — HTML format for Deep Improve run reports.
@@ -0,0 +1,59 @@
1
+ # Daily curation automation — the compounding pass on a timer
2
+
3
+ The third trigger of the work-driven path (the other two: the PreCompact/SessionEnd
4
+ hook and explicit milestones). This is the harness's existing **Continuous
5
+ Improvement** (Maintenance Pass / Micro-Improve / Deep Improve) promoted to a
6
+ **first-class, portable, scheduled** automation — "the agent goes for a walk" on a
7
+ timer, not only when asked.
8
+
9
+ **Portable definition + Claude-Code reliability** (same pattern as the hooks): the
10
+ spec below works on any assistant as a protocol; on Claude Code, wire a real daily
11
+ cron via the `schedule` skill pointed at this prompt.
12
+
13
+ ## Purpose
14
+
15
+ Run once per day, at a quiet hour, to keep the second brain alive:
16
+
17
+ - process pending `raw/worklog/` and `inbox/` material into `wiki/`
18
+ - strengthen weak / low-score pages; fill one open gap
19
+ - repair links and the graph (resolve broken wikilinks, add `## Related` where proper nouns recur)
20
+ - mark `stale` pages whose sources moved on
21
+ - record what changed in `wiki/log.md`
22
+
23
+ ## Suggested schedule
24
+
25
+ Daily, at a quiet hour when the user is unlikely to be editing the vault.
26
+
27
+ ## Scope (paths)
28
+
29
+ `raw/worklog/`, `inbox/`, `raw/`, `wiki/`, `wiki/harness/`.
30
+
31
+ ## Prompt
32
+
33
+ ```text
34
+ Run the daily curation pass for this 02-DOCS second brain.
35
+
36
+ Use the harness wiki-protocol.md as the contract. Compile pending raw/worklog/
37
+ and inbox/ material into wiki/ pages (update existing before creating new),
38
+ keep frontmatter + wikilinks consistent, append significant decisions to
39
+ wiki/harness/decisions.md, refresh the .base-backed navigation, recompute
40
+ scores.json + the score: property, and append a dated entry to wiki/log.md.
41
+
42
+ Be conservative. If the topic map no longer fits, record a recommendation in
43
+ wiki/gaps.md or a page's Open Questions instead of moving large parts of the
44
+ vault without explicit approval.
45
+ ```
46
+
47
+ ## Expected outcome (one of)
48
+
49
+ - worklog/inbox material distilled; `status` flipped to processed
50
+ - maintenance improvements to links, scores, `.base` views, or stale flags
51
+ - a `wiki/log.md` entry explaining what was checked and what remains open
52
+ - no file changes when there is genuinely nothing useful to do
53
+
54
+ ## Safety
55
+
56
+ - Do not rewrite or delete raw sources.
57
+ - Do not perform large taxonomy reorganizations without explicit approval.
58
+ - Do not create pages from weak connections just to look busy.
59
+ - Prefer small, compounding improvements over big sweeps.
@@ -0,0 +1,96 @@
1
+ # Obsidian scaffolding — make `02-DOCS/` open as a vault
2
+
3
+ Materialized during **Initialization** (see `wiki-protocol.md`). Turns the wiki
4
+ into a native Obsidian vault: graph, backlinks, Properties, and Bases — with **no
5
+ vector DB, no embeddings, no RAG**. Navigation is structure (links + frontmatter),
6
+ not semantic search. Do NOT add embedding/semantic-search plugins; that breaks the
7
+ thesis. Obsidian core only.
8
+
9
+ The point a human opens the vault at (the "base folder") is `02-DOCS/` itself —
10
+ not the repo root. Obsidian writes its config into `02-DOCS/.obsidian/`.
11
+
12
+ ## `02-DOCS/.gitignore` (additions)
13
+
14
+ ```gitignore
15
+ # Obsidian per-machine state (the rest of .obsidian/ — themes, bases, config — is tracked)
16
+ .obsidian/workspace*.json
17
+ .obsidian/cache
18
+ # regenerated / per-run surfaces
19
+ wiki/dashboard.html
20
+ audits/*.html
21
+ inbox/_processed/
22
+ ```
23
+
24
+ ## `02-DOCS/attachments/README.md`
25
+
26
+ ```markdown
27
+ # attachments
28
+
29
+ Shared binaries referenced from wiki pages (images, PDFs, diagrams) when they are
30
+ not bundled with a specific raw source. Link them from the page that depends on
31
+ them. Source-bundled originals stay in `raw/<topic>/_originals/`.
32
+ ```
33
+
34
+ ## `02-DOCS/.obsidian/app.json` (attachment folder)
35
+
36
+ ```json
37
+ {
38
+ "attachmentFolderPath": "attachments",
39
+ "newLinkFormat": "shortest",
40
+ "useMarkdownLinks": false
41
+ }
42
+ ```
43
+
44
+ `useMarkdownLinks: false` makes new internal links wikilinks. `userIgnoreFilters`
45
+ (Settings → Files & Links → Excluded files) should hide noise from search/graph:
46
+ `raw/_originals/`, `inbox/_processed/`, `audits/`.
47
+
48
+ ## `.base` views — the human navigation (replace hand-maintained nav)
49
+
50
+ These supersede manual upkeep of `index.md`/`dashboard.html` for humans;
51
+ `index.md` and `scores.json` remain as the machine layer + fallback.
52
+
53
+ ### `02-DOCS/wiki/Articles.base`
54
+
55
+ ```yaml
56
+ filters:
57
+ and:
58
+ - type == "article"
59
+ views:
60
+ - type: table
61
+ name: All Articles
62
+ order: [file.name, topic, status, score, updated]
63
+ sort:
64
+ - property: score
65
+ direction: DESC
66
+ ```
67
+
68
+ ### `02-DOCS/wiki/Worklog.base`
69
+
70
+ ```yaml
71
+ filters:
72
+ and:
73
+ - type == "worklog"
74
+ views:
75
+ - type: table
76
+ name: Worklog
77
+ order: [file.name, topic, date, status]
78
+ sort:
79
+ - property: date
80
+ direction: DESC
81
+ ```
82
+
83
+ ### `02-DOCS/wiki/Decisions.base`
84
+
85
+ ```yaml
86
+ filters:
87
+ and:
88
+ - type == "decision"
89
+ views:
90
+ - type: table
91
+ name: Decisions
92
+ order: [file.name, topic, status, updated]
93
+ sort:
94
+ - property: updated
95
+ direction: DESC
96
+ ```
@@ -1,7 +1,19 @@
1
+ ---
2
+ title: {Title}
3
+ aliases: [{old-slug}]
4
+ tags: []
5
+ type: article
6
+ topic: {topic}
7
+ status: draft
8
+ sources: []
9
+ updated: {YYYY-MM-DD}
10
+ score: 0.0
11
+ ---
12
+
1
13
  # {Title}
2
14
 
3
15
  > Sources: {Author1, YYYY-MM-DD; Author2, YYYY-MM-DD}
4
- > Raw: [{source1}](../../raw/{topic1}/{filename1}.md); [{source2}](../../raw/{topic2}/{filename2}.md)
16
+ > Raw: [[{raw-source-1}]]; [[{raw-source-2}]]
5
17
 
6
18
  ## Overview
7
19
 
@@ -11,10 +23,21 @@
11
23
 
12
24
  {Synthesize a coherent structure from the source material. Do not copy source text verbatim; distill and reorganize. Use blockquotes sparingly for particularly important original phrasing.}
13
25
 
14
- {OPTIONAL — include this section only when cross-references exist:}
15
-
16
- ## See Also
17
-
18
- {Cross-references to related wiki articles. Maintained during lint. Use relative links:
19
- - Same topic: [Other Article](other-article.md)
20
- - Different topic: [Other Article](../other-topic/other-article.md)}
26
+ ## Related
27
+
28
+ {OPTIONAL include only when cross-references exist. Maintained during lint. Use wikilinks so the link survives renames and shows in the Obsidian graph + backlinks:
29
+ - Same or different topic: `- [[Other Article]] — why it connects.`
30
+ - With display text: `- [[Other Article|how we say it here]] — why it connects.`}
31
+
32
+ <!--
33
+ FRONTMATTER CONTRACT (this is what powers Obsidian Properties + Bases + graph):
34
+ - title human-readable; the H1 matches it.
35
+ - aliases keep the old kebab slug here so pre-migration links/wikilinks still resolve.
36
+ - tags cross-cutting qualities ONLY — never the main category (that is `topic`).
37
+ - type article | decision | worklog | brief | spec | profile
38
+ - topic the wiki/<topic>/ folder, one level. Inferred from content, never hardcoded.
39
+ - status draft | stable | stale (lifecycle; filterable in a Base).
40
+ - sources wikilinks to raw/ pages this was distilled from (cite your evidence).
41
+ - updated YYYY-MM-DD of the last meaningful edit.
42
+ - score mirror of scores.json, written by the Maintenance Pass (single writer → no drift).
43
+ -->
@@ -1,13 +1,18 @@
1
1
  # Knowledge Base Index
2
2
 
3
+ > **Human navigation lives in the `.base` views** (`Articles.base`, `Worklog.base`,
4
+ > `Decisions.base`) — live tables over frontmatter, sorted by score/status/date.
5
+ > This index is the **machine-readable catalog + fallback** the agent maintains;
6
+ > it is not the primary surface a human browses in Obsidian.
7
+
3
8
  ## {topic-name}
4
9
 
5
10
  {One-line description of this topic.}
6
11
 
7
12
  | Article | Summary | Updated | Score |
8
13
  |---------|---------|---------|-------|
9
- | [{Article Title}]({topic-name}/{article}.md) | {One-line summary} | {YYYY-MM-DD} | {N.N} |
10
- | [{Archived Article}]({topic-name}/{archived}.md) | [Archived] {One-line summary} | {YYYY-MM-DD} | {N.N} |
14
+ | [[{Article Title}]] | {One-line summary} | {YYYY-MM-DD} | {N.N} |
15
+ | [[{Archived Article}]] | [Archived] {One-line summary} | {YYYY-MM-DD} | {N.N} |
11
16
 
12
17
  ## {another-topic}
13
18
 
@@ -15,7 +20,7 @@
15
20
 
16
21
  | Article | Summary | Updated | Score |
17
22
  |---------|---------|---------|-------|
18
- | [{Article Title}]({another-topic}/{article}.md) | {One-line summary} | {YYYY-MM-DD} | {N.N} |
23
+ | [[{Article Title}]] | {One-line summary} | {YYYY-MM-DD} | {N.N} |
19
24
 
20
25
  > **Score**: composite quality score (inbound links, source count, cited count,
21
26
  > freshness; minus conflicts and orphan penalty). Regenerated on every
@@ -12,9 +12,11 @@ skill required. When the parent skill (`SKILL.md`) reaches Phase 4 step 8
12
12
 
13
13
  - [The paradigm — chaos in, knowledge out](#the-paradigm--chaos-in-knowledge-out)
14
14
  - [Architecture](#architecture) · [Format split: markdown for state, HTML for surfaces](#format-split-markdown-for-state-html-for-surfaces)
15
+ - [The vault is Obsidian-native](#the-vault-is-obsidian-native)
15
16
  - [Initialization](#initialization)
16
17
  - [Ingest](#ingest) · [Fetch](#fetch-raw) · [Compile](#compile-wiki) · [Cascade Updates](#cascade-updates) · [Post-Ingest](#post-ingest)
17
18
  - [Inbox Sweep — "el agente sale a pasear"](#inbox-sweep--el-agente-sale-a-pasear)
19
+ - [Worklog Sweep — work-driven capture](#worklog-sweep--work-driven-capture)
18
20
  - [Query](#query)
19
21
  - [Lint](#lint) · [Deterministic Checks](#deterministic-checks-auto-fix) · [Heuristic Checks](#heuristic-checks-report-only)
20
22
  - [Continuous Improvement](#continuous-improvement) — Maintenance Pass / Micro-Improve / Deep Improve
@@ -144,6 +146,18 @@ Templates live alongside this file in `references/`:
144
146
 
145
147
  ---
146
148
 
149
+ ## The vault is Obsidian-native
150
+
151
+ `02-DOCS/` opens directly as an Obsidian vault (the human's "base folder" is
152
+ `02-DOCS/` itself, not the repo root). The agent writes the wiki; the human
153
+ **reads** it in Obsidian — graph, backlinks, Properties, and `.base` views — which
154
+ is exactly the Karpathy split. Navigation is **structure** (wikilinks + frontmatter
155
+ + Bases), not semantic similarity: **no vector DB, no embeddings, no RAG**, and no
156
+ embedding/search plugins. The `.base` views become the human navigation; `index.md`
157
+ + `scores.json` remain the machine layer + fallback. The exact scaffolding (the
158
+ `.base` files, `.obsidian/app.json`, attachments, `.gitignore`, excluded files) is
159
+ materialized from `obsidian-scaffolding.md` during Initialization.
160
+
147
161
  ## Initialization
148
162
 
149
163
  Triggers on the first Ingest. Check whether `02-DOCS/raw/` and `02-DOCS/wiki/`
@@ -162,11 +176,21 @@ exist. Create only what is missing; never overwrite existing files:
162
176
  - `02-DOCS/audits/` directory (with `.gitkeep`) — holds per-run audit reports
163
177
  from the parent skill (`audit-YYYY-MM-DD-HHMM.html`). May already exist if
164
178
  Phase 2 of the parent skill created it eagerly to write the first audit.
179
+ - `02-DOCS/raw/worklog/` directory (with `.gitkeep`) — the **work-driven on-ramp**
180
+ (see "Worklog Sweep"); holds `YYYY-MM-DD-<slug>.md` captures of what we did.
181
+ - `02-DOCS/attachments/` directory + `README.md` — shared binaries (Obsidian's
182
+ default attachment folder), from `obsidian-scaffolding.md`.
183
+ - `02-DOCS/wiki/Articles.base`, `Worklog.base`, `Decisions.base` — the human
184
+ navigation views, from `obsidian-scaffolding.md`.
185
+ - `02-DOCS/.obsidian/app.json` — sets the attachment folder and wikilink defaults,
186
+ from `obsidian-scaffolding.md`.
165
187
  - `02-DOCS/.gitignore` — at minimum:
166
188
  - `wiki/dashboard.html` (regenerated by Maintenance Pass)
167
189
  - `audits/*.html` (per-run audit artifacts from the parent skill)
168
190
  - `inbox/_processed/` (sweep archive — bulky, derivable; the durable copy
169
191
  of every binary lives in `raw/<topic>/_originals/`)
192
+ - `.obsidian/workspace*.json` and `.obsidian/cache` (Obsidian per-machine state;
193
+ the rest of `.obsidian/` — themes, bases, config — is tracked)
170
194
  - `wiki/reports/*.html` is **not** gitignored — Deep Improve reports are
171
195
  durable historical records, unlike the per-run audit snapshots.
172
196
 
@@ -341,6 +365,67 @@ Append to `02-DOCS/wiki/log.md`:
341
365
 
342
366
  ---
343
367
 
368
+ ## Worklog Sweep — work-driven capture
369
+
370
+ The Inbox Sweep turns files the user *dropped* into knowledge. The **Worklog
371
+ Sweep** turns what we *did* into knowledge — the second on-ramp. A work session is
372
+ just another source of chaos: it lands in `raw/worklog/` and is Compiled into
373
+ `wiki/` through the exact same pipeline. No parallel system.
374
+
375
+ ### What it captures
376
+
377
+ One `raw/worklog/YYYY-MM-DD-<slug>.md` per meaningful unit of work, in the format
378
+ of `wiki-worklog-template.md` (frontmatter `type: worklog`, `topic`, `date`,
379
+ `status: unprocessed`): what we did, why (intent + decisions), files touched
380
+ (`path:line`), outcome with evidence, open questions/next, commands. This
381
+ generalizes the SDD session-summary convention to *any* work.
382
+
383
+ ### Triggers
384
+
385
+ - **Hook — `PreCompact` / `SessionEnd`** (Claude Code): fires right before context
386
+ is lost or the session ends. The hook only *reminds*; the agent writes the
387
+ worklog (Karpathy: the LLM writes). Wired by `targets/` → `.rsc/worklog-checkpoint.sh`.
388
+ - **Explicit milestone**: after a commit or a shipped feature, capture a worklog.
389
+ - **Daily curation automation**: distills any pending worklog raw on a timer (see
390
+ Continuous Improvement and `daily-curation-automation.md`).
391
+
392
+ ### Throttle — capture signal, not noise
393
+
394
+ Write a worklog **only** when there is durable signal: files changed, a decision
395
+ was made, or a milestone was hit. **Skip** pure read/answer turns and questions
396
+ with no change. Never manufacture a worklog "to look busy" — that is the same
397
+ safety rule the curation pass honors.
398
+
399
+ ### Steps
400
+
401
+ 1. **Capture.** Write the worklog to `raw/worklog/YYYY-MM-DD-<slug>.md`
402
+ (`status: unprocessed`). Infer `topic` from content.
403
+ 2. **Compile.** Run the normal Compile (Fetch is a no-op — the worklog is already
404
+ `raw`): distill durable points into `wiki/<topic>/` articles (update existing
405
+ before creating new), add wikilink cross-refs + `## Related`, cascade.
406
+ 3. **Route decisions.** Every significant decision is appended to
407
+ `wiki/harness/decisions.md` (append-only, the "siempre 3 opciones" shape).
408
+ 4. **Close.** Flip the worklog's `status` to `processed` (the raw stays as
409
+ evidence — never deleted or rewritten) and append to `wiki/log.md`.
410
+
411
+ ### Post-Sweep log
412
+
413
+ Append to `02-DOCS/wiki/log.md`:
414
+
415
+ ```markdown
416
+ ## [YYYY-MM-DD] worklog | <slug> → <A> articles touched
417
+ ```
418
+
419
+ ### Worklog Sweep safety rails
420
+
421
+ - **Evidence is immutable.** The worklog raw is never edited for style after the
422
+ fact; only its `status` flips. Distillation happens in `wiki/`, not in the raw.
423
+ - **No invention.** Capture what actually happened (cite commands/outputs); do not
424
+ embellish outcomes. "Done" requires evidence.
425
+ - **Throttled.** No worklog for trivial turns (see Throttle above).
426
+
427
+ ---
428
+
344
429
  ## Query
345
430
 
346
431
  Search the wiki and answer questions. Examples of triggers:
@@ -635,15 +720,25 @@ These apply to all Layers:
635
720
 
636
721
  ## Conventions
637
722
 
638
- - Standard markdown with relative links throughout.
723
+ - **Obsidian-friendly markdown.** Internal cross-references use **wikilinks**
724
+ (`[[Page]]` / `[[Page|alias]]`) — resolved by filename, no path needed — so the
725
+ Obsidian graph + backlinks come for free and survive moves. (Legacy relative
726
+ markdown links still resolve in Obsidian; the migration pass converts them.)
727
+ - **Frontmatter on curated articles.** Every `wiki/<topic>/` article carries the
728
+ YAML frontmatter from `wiki-article-template.md` (`title, aliases, tags, type,
729
+ topic, status, sources, updated, score`). This is what powers Obsidian
730
+ Properties + the `.base` views. Operational files (`index.md`, `log.md`,
731
+ `gaps.md`) may use simpler formats.
732
+ - **Human-readable wiki filenames** (`Month-End Close.md`) for clean graph nodes;
733
+ the old kebab slug goes in `aliases` so prior links/wikilinks still resolve.
734
+ `raw/` and `raw/worklog/` filenames stay kebab + date (chaos, not display).
639
735
  - `wiki/` supports one level of topic subdirectories only. No deeper
640
736
  nesting.
641
737
  - Today's date for log entries, Collected dates, and Archived dates.
642
738
  Updated dates reflect when the article's knowledge content last changed.
643
739
  Published dates come from the source (use `Unknown` when unavailable).
644
- - Inside `wiki/` files, all markdown links use paths relative to the
645
- current file. In conversation output, use project-root-relative paths
646
- (e.g., `02-DOCS/wiki/topic/article.md`).
740
+ - Inside `wiki/` files, internal references use wikilinks. In conversation
741
+ output, use project-root-relative paths (e.g., `02-DOCS/wiki/topic/Article.md`).
647
742
  - Ingest updates both `02-DOCS/wiki/index.md` and `02-DOCS/wiki/log.md`.
648
743
  Archive (from Query) updates both. Lint updates `02-DOCS/wiki/log.md`
649
744
  (and `02-DOCS/wiki/index.md` only when auto-fixing index entries). Plain
@@ -0,0 +1,56 @@
1
+ # Worklog raw template — `raw/worklog/<YYYY-MM-DD>-<slug>.md`
2
+
3
+ The **work-driven on-ramp**. A Worklog Sweep writes one of these per meaningful
4
+ unit of work — what we *did*, not what someone dropped in `inbox/`. It is `raw`
5
+ (evidence: preserved, never edited after the fact) and is Compiled into `wiki/`
6
+ like any other source. The session is just another source of chaos.
7
+
8
+ **Throttle — do NOT write a worklog for:** pure read/answer turns, questions with
9
+ no file change, no decision, and no commit. Capture only durable signal. Never
10
+ manufacture a worklog "to look busy."
11
+
12
+ ```yaml
13
+ ---
14
+ type: worklog
15
+ topic: {inferred-topic}
16
+ date: {YYYY-MM-DD}
17
+ status: unprocessed
18
+ sources: []
19
+ ---
20
+ ```
21
+
22
+ ## What we did
23
+
24
+ {Concrete changes / features / fixes — one bullet each. Plain, factual.}
25
+
26
+ ## Why
27
+
28
+ {Intent and the decisions taken. Every *significant* decision is ALSO appended to
29
+ `wiki/harness/decisions.md` (append-only, with the 3-options shape) during Compile.}
30
+
31
+ ## Files touched
32
+
33
+ - `{path}:{line}` — {what changed}
34
+
35
+ ## Outcome
36
+
37
+ {Verdict: shipped & verified / partial / blocked. Include the evidence — test
38
+ output, command result, screenshot path. No "done" without proof.}
39
+
40
+ ## Open questions / next
41
+
42
+ - {What remains, what to pick up next session.}
43
+
44
+ ## Commands
45
+
46
+ - `{command}` — {result}
47
+
48
+ <!--
49
+ LIFECYCLE: written by the Worklog Sweep → status: unprocessed. The Compile step
50
+ distills durable points into wiki/<topic>/ articles (update existing before
51
+ creating new), cross-links, cascades, appends decisions to decisions.md, then
52
+ flips this file's status to processed (the raw stays as evidence; it is not
53
+ deleted or rewritten). Triggers that fire a Worklog Sweep: a PreCompact/SessionEnd
54
+ hook (Claude Code), an explicit milestone (a commit / a shipped feature), and the
55
+ daily curation automation. See `wiki-protocol.md` → "Worklog Sweep".
56
+ -->
@@ -55,6 +55,10 @@ Before discovery, before any recommendation, write the profile to `02-DOCS` and
55
55
 
56
56
  If `02-DOCS/` does not yet exist (greenfield), create `02-DOCS/wiki/harness/` now — just enough to hold these two files. That, plus the `CLAUDE.md` Knowledge-map link, is everything `init` writes; ALL other `01-TOOLS/` + `02-DOCS/` scaffolding is the `harness` skill's job.
57
57
 
58
+ ### Opt-out marker — `.rsc/.no-harness`
59
+
60
+ A freshly-installed session auto-starts `init` while `02-DOCS/wiki/harness/user-profile.md` is absent (the `suggest` Onboarding gate + claude's SessionStart hook). If the user does not want a harness in this repo (e.g. they installed only code skills), write an empty `.rsc/.no-harness` — this permanently silences the auto-start here even before a profile exists. Completing first contact (which writes `user-profile.md`) also silences it. The marker is project-local; commit it so the "no harness here" decision is shared by the team.
61
+
58
62
  ### How every skill adapts to the dial
59
63
 
60
64
  Every rsc skill MUST read `user-profile.md` at the start of a session and adapt:
@@ -24,6 +24,16 @@ Rules:
24
24
  - Never recommend something already installed (`npx @ericrisco/rsc list`).
25
25
  - One suggestion at a time. Don't interrupt the flow for nice-to-haves.
26
26
 
27
+ ## Onboarding gate (first contact)
28
+
29
+ Before handling the first request of the session, check the workspace state:
30
+
31
+ - If `02-DOCS/wiki/harness/user-profile.md` is **missing** AND `.rsc/.no-harness` is **missing**, the harness has never been set up here — your FIRST action is to invoke `init` (auto-onboarding), which opens with the two gauging questions (technical level + accompaniment dial). Don't wait to be asked; don't start the user's task until first contact is done.
32
+ - If the user declines or says they don't want a harness here ("sin harness", "solo código", "no quiero esto") — create an empty `.rsc/.no-harness` and never auto-start `init` in this repo again. Confirm in one line.
33
+ - Once `02-DOCS/wiki/harness/user-profile.md` exists, this gate is inert — never re-onboard.
34
+
35
+ This is the universal layer every assistant reads. On Claude Code a SessionStart hook also prints this reminder deterministically, but the rule above is what makes it fire everywhere.
36
+
27
37
  ## Orientación (siempre)
28
38
 
29
39
  Cierra cada turno con el **bloque-brújula** (📍 dónde estás · ✅ qué hiciste · 🧭 por qué · ➡️ siguiente, terminando en pregunta), calibrado al dial de `02-DOCS/wiki/harness/user-profile.md`. **Nunca termines en seco.** Protocolo completo: skill `orient` → `skills/orient/references/orientation-contract.md`. (Defiere a `suggest` el "¿instalo la skill que falta?".)
package/targets/claude.js CHANGED
@@ -1,22 +1,56 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
- import { dirname } from 'node:path';
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync, chmodSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
3
4
  import { linkOrCopy } from './index.js';
4
5
 
5
6
  export function writeSkill(id, fromDir, toPath) {
6
7
  return linkOrCopy(fromDir, toPath);
7
8
  }
8
9
 
10
+ // SessionStart runs a project-local session-start.sh: it cats suggest's always-on
11
+ // body (preserving prior behavior) and appends an onboarding banner when the
12
+ // workspace has no harness profile yet. We materialize the script next to the
13
+ // shared base and point the hook at it. Any prior rsc SessionStart entry (the old
14
+ // `cat …/suggest/SKILL.md` form or a previous script form) is dropped before we
15
+ // add the current one — idempotent, and it migrates legacy hooks in place. Other
16
+ // (non-rsc) SessionStart hooks are preserved.
9
17
  export function wireHook(paths) {
18
+ const scriptDest = join(paths.projectRoot, '.rsc', 'session-start.sh');
19
+ mkdirSync(dirname(scriptDest), { recursive: true });
20
+ copyFileSync(join(dirname(fileURLToPath(import.meta.url)), 'session-start.sh'), scriptDest);
21
+ chmodSync(scriptDest, 0o755);
22
+
23
+ const suggestMd = `${paths.skillDir('suggest')}/SKILL.md`;
24
+ const cmd = `bash "${scriptDest}" "${suggestMd}" "${paths.projectRoot}"`;
25
+
10
26
  const file = paths.hookTarget;
11
27
  const settings = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : {};
12
28
  settings.hooks ||= {};
13
29
  settings.hooks.SessionStart ||= [];
14
- const cmd = `cat "${paths.skillDir('suggest')}/SKILL.md"`;
15
- const already = JSON.stringify(settings.hooks.SessionStart).includes('skills/rsc/suggest');
16
- if (!already) {
17
- settings.hooks.SessionStart.push({ hooks: [{ type: 'command', command: cmd }] });
30
+ settings.hooks.SessionStart = settings.hooks.SessionStart.filter((e) => {
31
+ const s = JSON.stringify(e);
32
+ return !s.includes('skills/rsc/suggest') && !s.includes('.rsc/session-start.sh');
33
+ });
34
+ settings.hooks.SessionStart.push({ hooks: [{ type: 'command', command: cmd }] });
35
+
36
+ // Worklog checkpoint: PreCompact + SessionEnd run a project-local
37
+ // worklog-checkpoint.sh that reminds the agent to capture what we did this
38
+ // session into 02-DOCS/raw/worklog/ (the work-driven on-ramp). Silent when the
39
+ // workspace has no harness wiki. Registered idempotently on both events, with
40
+ // any prior rsc worklog-checkpoint entry dropped first.
41
+ const wlDest = join(paths.projectRoot, '.rsc', 'worklog-checkpoint.sh');
42
+ copyFileSync(join(dirname(fileURLToPath(import.meta.url)), 'worklog-checkpoint.sh'), wlDest);
43
+ chmodSync(wlDest, 0o755);
44
+ const wlCmd = `bash "${wlDest}" "${paths.projectRoot}"`;
45
+ for (const event of ['PreCompact', 'SessionEnd']) {
46
+ settings.hooks[event] ||= [];
47
+ settings.hooks[event] = settings.hooks[event].filter(
48
+ (e) => !JSON.stringify(e).includes('.rsc/worklog-checkpoint.sh'),
49
+ );
50
+ settings.hooks[event].push({ hooks: [{ type: 'command', command: wlCmd }] });
18
51
  }
52
+
19
53
  mkdirSync(dirname(file), { recursive: true });
20
54
  writeFileSync(file, JSON.stringify(settings, null, 2) + '\n');
21
- return [file];
55
+ return [file, scriptDest, wlDest];
22
56
  }
package/targets/index.js CHANGED
@@ -105,6 +105,7 @@ export function targetPaths(target, home = homedir(), cwd = process.cwd()) {
105
105
  const rootAbs = join(cwd, ...s.root.split('/'));
106
106
  return {
107
107
  root: rootAbs,
108
+ projectRoot: cwd,
108
109
  skillDir: (id) => (s.skillExt ? join(rootAbs, `${id}${s.skillExt}`) : join(rootAbs, id)),
109
110
  stateFile: join(rootAbs, '.rsc-state.json'),
110
111
  hookTarget: join(cwd, ...s.hook.split('/')),
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ # rsc SessionStart payload (claude). Wired by targets/claude.js.
3
+ # $1 = absolute path to suggest's SKILL.md $2 = absolute project root
4
+ # Always emits suggest's always-on body; appends an onboarding banner only when
5
+ # the workspace has no harness profile yet and the user has not opted out.
6
+ set -u
7
+
8
+ cat "$1" 2>/dev/null
9
+
10
+ profile="$2/02-DOCS/wiki/harness/user-profile.md"
11
+ optout="$2/.rsc/.no-harness"
12
+
13
+ if [ ! -f "$profile" ] && [ ! -f "$optout" ]; then
14
+ cat <<'BANNER'
15
+
16
+ ===== rsc onboarding =====
17
+ Fresh setup: 02-DOCS/wiki/harness/user-profile.md is missing.
18
+ ACTION: invoke `init` now (first contact: technical level + accompaniment dial) before the task.
19
+ If the user does not want a harness here: create .rsc/.no-harness
20
+ ==========================
21
+ BANNER
22
+ fi
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # rsc Worklog checkpoint payload (claude). Wired by targets/claude.js onto the
3
+ # PreCompact and SessionEnd hooks.
4
+ # $1 = absolute project root
5
+ # Reminds the agent to run a Worklog Sweep (capture what we did this session into
6
+ # 02-DOCS/raw/worklog/ so the harness can compile it into the wiki). The hook only
7
+ # REMINDS — the agent writes the worklog (Karpathy: the LLM writes the wiki).
8
+ # Silent when this workspace has no harness wiki yet (nothing to document into).
9
+ set -u
10
+
11
+ root="${1:-$PWD}"
12
+
13
+ # No harness wiki here → nothing to do. Stay silent.
14
+ [ -d "$root/02-DOCS/wiki" ] || exit 0
15
+
16
+ cat <<'BANNER'
17
+
18
+ ===== rsc worklog checkpoint =====
19
+ If this session did meaningful work (files changed, a decision made, a commit),
20
+ run a WORKLOG SWEEP before context is lost:
21
+ 1. Write 02-DOCS/raw/worklog/<YYYY-MM-DD>-<slug>.md using the harness
22
+ wiki-worklog-template.md (what we did · why · files touched · outcome · next).
23
+ 2. Compile it into wiki/ (update existing articles first; wikilinks + Related);
24
+ append significant decisions to 02-DOCS/wiki/harness/decisions.md.
25
+ Skip entirely if this was a pure read/answer turn with no changes.
26
+ ==================================
27
+ BANNER