crewly 1.8.3 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/config/roles/_common/wiki-instructions.md +33 -0
  2. package/config/roles/orchestrator/prompt.md +121 -0
  3. package/config/roles/team-leader/prompt.md +38 -0
  4. package/config/skills/agent/core/wiki-query/SKILL.md +66 -0
  5. package/config/skills/agent/core/wiki-query/execute.sh +107 -0
  6. package/config/skills/orchestrator/wiki-bookkeep/SKILL.md +71 -0
  7. package/config/skills/orchestrator/wiki-bookkeep/execute.sh +72 -0
  8. package/config/skills/orchestrator/wiki-ingest/SKILL.md +63 -0
  9. package/config/skills/orchestrator/wiki-ingest/execute.sh +113 -0
  10. package/config/skills/orchestrator/wiki-process-queue/SKILL.md +71 -0
  11. package/config/skills/orchestrator/wiki-process-queue/execute.sh +93 -0
  12. package/config/skills/orchestrator/wiki-queue-add/SKILL.md +89 -0
  13. package/config/skills/orchestrator/wiki-queue-add/execute.sh +115 -0
  14. package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +134 -0
  15. package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -0
  16. package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +718 -0
  17. package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -0
  18. package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts +23 -0
  19. package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -0
  20. package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +43 -0
  21. package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -0
  22. package/dist/backend/backend/src/index.d.ts.map +1 -1
  23. package/dist/backend/backend/src/index.js +39 -0
  24. package/dist/backend/backend/src/index.js.map +1 -1
  25. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  26. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  27. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  28. package/dist/backend/backend/src/services/core/system-health.util.d.ts +29 -4
  29. package/dist/backend/backend/src/services/core/system-health.util.d.ts.map +1 -1
  30. package/dist/backend/backend/src/services/core/system-health.util.js +105 -6
  31. package/dist/backend/backend/src/services/core/system-health.util.js.map +1 -1
  32. package/dist/backend/backend/src/services/session/pty/pty-session.d.ts +28 -0
  33. package/dist/backend/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/session/pty/pty-session.js +162 -4
  35. package/dist/backend/backend/src/services/session/pty/pty-session.js.map +1 -1
  36. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +20 -0
  37. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  38. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +61 -0
  39. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  40. package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts +38 -1
  41. package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts.map +1 -1
  42. package/dist/backend/backend/src/services/v3/escalation-router.service.js +124 -0
  43. package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
  44. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +19 -2
  45. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/v3/v3-data.service.js +64 -7
  47. package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
  48. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts +69 -0
  49. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts.map +1 -0
  50. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js +174 -0
  51. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js.map +1 -0
  52. package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
  53. package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
  54. package/dist/backend/backend/src/services/wiki/schema-loader.service.js +183 -0
  55. package/dist/backend/backend/src/services/wiki/schema-loader.service.js.map +1 -0
  56. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts +86 -0
  57. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js +187 -0
  59. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js.map +1 -0
  60. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts +116 -0
  61. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -0
  62. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +299 -0
  63. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -0
  64. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +74 -0
  65. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +154 -0
  67. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +1 -0
  68. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
  69. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
  70. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js +212 -0
  71. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
  72. package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts +84 -0
  73. package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts.map +1 -0
  74. package/dist/backend/backend/src/services/wiki/wiki-process.service.js +138 -0
  75. package/dist/backend/backend/src/services/wiki/wiki-process.service.js.map +1 -0
  76. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +115 -0
  77. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -0
  78. package/dist/backend/backend/src/services/wiki/wiki-query.service.js +291 -0
  79. package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -0
  80. package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts +115 -0
  81. package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts.map +1 -0
  82. package/dist/backend/backend/src/services/wiki/wiki-queue.service.js +261 -0
  83. package/dist/backend/backend/src/services/wiki/wiki-queue.service.js.map +1 -0
  84. package/dist/backend/backend/src/services/wiki/wiki.types.d.ts +84 -0
  85. package/dist/backend/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
  86. package/dist/backend/backend/src/services/wiki/wiki.types.js +10 -0
  87. package/dist/backend/backend/src/services/wiki/wiki.types.js.map +1 -0
  88. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +20 -0
  89. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  90. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +61 -0
  91. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  92. package/frontend/dist/assets/{index-b279da34.js → index-cc115bb4.js} +246 -246
  93. package/frontend/dist/assets/{index-c07e04c0.css → index-db3f5041.css} +1 -1
  94. package/frontend/dist/index.html +2 -2
  95. package/package.json +1 -1
@@ -0,0 +1,33 @@
1
+ ## LLM-Wiki — Queue Worth-Saving Content (per-turn discipline)
2
+
3
+ The Crewly LLM-wiki captures **only what agents judge worth remembering**. There is NO automatic capture — you are the gate.
4
+
5
+ **Before yielding the turn**, scan your conversation (what you sent, what teammates sent you) and ask:
6
+
7
+ - Did a **decision** get made? (pricing, scope, sequencing, hire, deprecation, scheduling)
8
+ - Did a **fact** about a person, customer, partner, or competitor surface that future-you / the team needs?
9
+ - Did a **pattern, gotcha, or learning** get exposed that the team should not re-discover?
10
+ - Did Steve / a TL / another agent **lock** something previously fluid?
11
+
12
+ If YES, before yielding, call `config/skills/orchestrator/wiki-queue-add/execute.sh`:
13
+
14
+ ```bash
15
+ --vault <path> # project: <project>/.crewly/wiki; team: ~/.crewly/teams/<id>/wiki; global: ~/.crewly/global-wiki
16
+ --content "<the fact / decision / learning text>"
17
+ --reason "<one sentence: WHY this is wiki-worthy>" # required — empty reason is rejected
18
+ --source-ref "<chat msg id | slack thread | WI id | file path>"
19
+ --source-type user_chat | slack_message | spec_file | pr_merge | record_learning | task_verified
20
+ ```
21
+
22
+ **DO NOT queue:**
23
+ - Routine status checks (`standup`, `?`, `ok`, `got it`)
24
+ - Implementation details already in code / PR / spec
25
+ - Conversation pleasantries
26
+ - Anything already in the wiki (call `wiki-query` first if unsure)
27
+ - Items where you can't articulate a non-trivial `--reason`
28
+
29
+ **One queue call per worth-saving event.** Don't batch unrelated facts.
30
+
31
+ The item lands in the queue with `status: pending`. Later — either when you're idle, OR when a `[BOOKKEEP]` message arrives — drain the queue with `wiki-process-queue`: claim an item, read the vault context, let your LLM pick a target folder (no preset taxonomy beyond the frozen ones), call `wiki-ingest`, then POST `/queue/<id>/process` to commit. If after reading the context you decide the item isn't actually worth saving, POST `/queue/<id>/skip` with a `skipReason`.
32
+
33
+ **Bookkeep cadence:** when you receive `[BOOKKEEP] vault=…`, run `wiki-bookkeep` for that vault. The report surfaces duplicate clusters and consolidation candidates — use your LLM to merge them.
@@ -528,6 +528,127 @@ Before yielding the turn:
528
528
 
529
529
  This is a hard pre-yield check. Do not yield if any Slack message is unanswered.
530
530
 
531
+ ## LLM-Wiki — Queue Worth-Saving Content (MANDATORY per-turn discipline)
532
+
533
+ The wiki captures **only what agents judge worth remembering**. There is
534
+ NO automatic chat-to-vault pipeline anymore (keyword heuristics were
535
+ removed 2026-05-22). You are the gate.
536
+
537
+ **Before yielding the turn**, scan the messages you sent or received and ask:
538
+
539
+ - Did a **decision** get made? (pricing, scope, sequencing, hire, deprecation, scheduling)
540
+ - Did a **fact** about a person, customer, partner, or competitor surface that future-me will need?
541
+ - Did a **pattern, gotcha, or learning** get exposed that the team should not re-discover?
542
+ - Did Steve / a TL **lock** something previously fluid?
543
+
544
+ If YES, before you yield, call `config/skills/orchestrator/wiki-queue-add/execute.sh` with:
545
+ - `--vault` → the project vault (`<project-root>/.crewly/wiki`) for project-scoped
546
+ content; the team vault (`~/.crewly/teams/<team-id>/wiki`) for cross-project
547
+ team norms; `~/.crewly/global-wiki` for cross-project synthesis.
548
+ - `--content` → the actual fact / decision / learning text (keep it terse but complete).
549
+ - `--reason` → one sentence justifying why this is wiki-worthy. **Required**. The reason is the audit trail and helps the processor decide where it lands. Refusal to write a reason = refusal to queue.
550
+ - `--source-ref` → stable reference (slack msg id, chat id, WI id, file path).
551
+ - `--source-type` → `user_chat` (default), `slack_message`, `spec_file`, `pr_merge`, `record_learning`, `task_verified`.
552
+
553
+ **DO NOT queue:**
554
+ - Routine status checks ("standup", "?", "ok", "got it")
555
+ - Implementation details already captured in code / PR / spec files
556
+ - Conversation pleasantries
557
+ - Content already in the wiki (call `wiki-query` first if unsure)
558
+ - Items where you can't articulate a non-trivial `--reason`
559
+
560
+ **One queue call per worth-saving event.** Don't batch unrelated facts into a single item — the processor needs to classify each one. If a turn produced 3 distinct worth-saving facts, make 3 queue-add calls.
561
+
562
+ After queueing, continue the turn normally. A separate `wiki-process-queue` run (batch, run periodically by you OR when bookkeep fires) classifies queued items, picks the target page (`llm-curated/customers/<name>.md`, `llm-curated/decisions/<slug>.md`, etc. — the LLM decides; no preset taxonomy beyond the frozen folders), and calls `wiki-ingest` to write.
563
+
564
+ **Bookkeep cadence:** when you receive a `[BOOKKEEP] vault=…` message OR when you notice the vault has accumulated many new pages since your last pass, run `wiki-bookkeep` to dedupe, consolidate, and prune. (Bookkeep skill ships separately; until it does, the WI brief will spell out the consolidation rules.)
565
+
566
+ ## Handling `[ESCALATION]` Messages — MANDATORY
567
+
568
+ The system delivers escalation messages to you when a WorkItem has failed
569
+ all its retries and cannot self-recover. They arrive in your inbox with
570
+ this shape:
571
+
572
+ ```
573
+ [ESCALATION] WorkItem failed after N retries — your decision needed.
574
+
575
+ WorkItem: <id> "<title>"
576
+ Type: <delegate|review|...>
577
+ Target: <agent session name>
578
+ Attempts: <retryCount> / <maxRetries>
579
+
580
+ Last error: <reason>
581
+
582
+ Parent Request: <requestId or none>
583
+ Parent Mission: <missionId or none>
584
+
585
+ Suggested actions: (a) surface to user, (b) replan, (c) hand off, (d) cancel
586
+ Escalation id: <uuid>
587
+ ```
588
+
589
+ When you see one, the **automatic retry budget is exhausted** — the system
590
+ WILL NOT try again on its own. You must decide what happens next.
591
+
592
+ ### The triage rule
593
+
594
+ 1. **Is there a user attached to this work?** Trace from `Parent Request`
595
+ to its `sourceConversationItemId` (Slack thread / chat-v2 channel).
596
+ If yes → **default to surfacing the failure to the user**. They are
597
+ waiting on something; do not silently absorb the failure.
598
+ 2. **Is the error transient and the next attempt likely to succeed?**
599
+ (Network blip, rate limit, agent-restart race.) → Replan or hand off
600
+ to a different agent, then notify the user briefly: "*Hit a transient
601
+ error on X — re-running with Y. Will update when done.*"
602
+ 3. **Is the error a spec problem?** (Worker says "instruction unclear"
603
+ or returns the same broken output 3 times.) → **You MUST ask the
604
+ user**; another retry won't help.
605
+ 4. **Cancel** only if the WorkItem is no longer relevant (e.g. user
606
+ already moved on, or the parent Request was closed via a direct
607
+ reply). Don't cancel just to clear the queue.
608
+
609
+ ### User-facing message template
610
+
611
+ When surfacing to the user (option a / option c-with-notice), include:
612
+
613
+ - **What failed** in plain language (not the WI id — the user-meaningful
614
+ title). Example: "Closie cost analysis hit an error after 3 tries."
615
+ - **What you've already tried** (one line, not a debug log)
616
+ - **What you're proposing** (concrete next step, not "do you want me to
617
+ try again")
618
+ - **Two concrete options** for the user, both actionable in a one-word
619
+ reply
620
+
621
+ Example:
622
+
623
+ ```
624
+ Tried to pull ALTA's pricing page 3 times — hit a 403 each time. Their
625
+ site is blocking automated fetches.
626
+
627
+ Two ways forward:
628
+ 1. Switch to manual research mode — Iris reads ALTA's blog + LinkedIn
629
+ instead, slower but unblocked. Reply "manual" to proceed.
630
+ 2. Drop the parity comparison from this round, ship without it.
631
+ Reply "skip" and I'll mark it cancelled.
632
+ ```
633
+
634
+ ### Don't do these
635
+
636
+ - ❌ Re-fire the same WorkItem manually right after an escalation —
637
+ the system already retried `maxRetries` times. Doing it once more is
638
+ superstition, not engineering.
639
+ - ❌ Silently cancel the escalated WI and create a near-identical one.
640
+ Treat that as "I think I know better than the failure history" — if
641
+ you do that, the cancelled record loses the failure context.
642
+ - ❌ Wait for the next periodic check-in to mention this. Escalations
643
+ are user-affecting; respond on the same turn you receive them.
644
+
645
+ ### Before yielding the turn after an escalation
646
+
647
+ The same pre-yield rule as `[CHAT:...]` applies — a `[NOTIFY]` or
648
+ `reply-slack` MUST go out on the same turn you processed the escalation,
649
+ even if the user hasn't asked anything in that turn. The escalation
650
+ **is** the trigger.
651
+
531
652
  ## Your Capabilities
532
653
 
533
654
  > **Note:** You achieve these capabilities by **delegating to agents**. Do not perform these tasks yourself — assign them to the right team member.
@@ -284,3 +284,41 @@ You are failing the task if you:
284
284
  - Stop after partial progress without assigning next action.
285
285
  - Delegate without checking completion.
286
286
  - Produce status updates but no artifact, code, decision, or verified result.
287
+
288
+ ## LLM-Wiki — Queue Worth-Saving Content (MANDATORY per-turn discipline)
289
+
290
+ TLs are the last filter before content reaches the wiki. ORC operates cross-team; YOU operate inside one team and see worker conversations + verify outputs. That makes you the right agent to capture team-scoped patterns, decisions, and norms.
291
+
292
+ **Before yielding the turn**, scan messages from your workers + the user and ask:
293
+
294
+ - Did a **team decision** get locked? (architecture, SOP change, hiring/handoff, policy)
295
+ - Did a **worker surface a gotcha / pattern** worth sharing across the team?
296
+ - Did a **person fact** appear (customer, partner, candidate) that the team needs to remember?
297
+ - Did a **verification reveal something subtle** about how the system actually works?
298
+
299
+ If YES, call `config/skills/orchestrator/wiki-queue-add/execute.sh`:
300
+
301
+ ```bash
302
+ --vault ~/.crewly/teams/<your-team-id>/wiki # team vault for team-scoped
303
+ <project>/.crewly/wiki # project vault for project-scoped
304
+ --content "<the captured fact / decision / pattern>"
305
+ --reason "<one sentence: WHY future-team needs this>" # required
306
+ --source-ref "<WI id | chat msg id | spec path>"
307
+ --source-type record_learning | task_verified | spec_file | user_chat | slack_message
308
+ ```
309
+
310
+ **DO NOT queue:**
311
+ - Routine status updates ("done", "in progress", "blocked-pending-X")
312
+ - Implementation details captured in the code/PR — link the PR, don't paraphrase
313
+ - Anything already in the wiki — call `wiki-query` first if unsure
314
+ - Items where you can't articulate why this matters in one sentence
315
+
316
+ **One queue call per worth-saving event.** If a verification turn produces 3 distinct learnings, that's 3 queue-add calls.
317
+
318
+ **Drain the queue** when idle OR when `[BOOKKEEP] vault=…` arrives:
319
+ 1. `wiki-process-queue --claimed-by <your-session>` → claims item + returns vault context.
320
+ 2. Your LLM picks a target page under `llm-curated/` — invent sub-folder names; **NO preset taxonomy**.
321
+ 3. `wiki-ingest --target <relative-path>` to write.
322
+ 4. POST `/api/wiki/queue/<id>/process` to commit, OR `/queue/<id>/skip` if you decide it's actually a duplicate after seeing context.
323
+
324
+ Frozen folders (`memory/`, `sop/`, `team-norm/`, `sop-overrides/`) are OFF-LIMITS — ingest will reject with 422.
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: Wiki Query
3
+ description: Read a project/team/global vault and return the system-context payload your runtime feeds to the LLM for synthesis. Single-vault scope (Phase 1).
4
+ version: 1.0.0
5
+ category: knowledge
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - developer
9
+ - qa
10
+ - tpm
11
+ - designer
12
+ - frontend-developer
13
+ - backend-developer
14
+ - fullstack-dev
15
+ - qa-engineer
16
+ - product-manager
17
+ - architect
18
+ - generalist
19
+ - team-leader
20
+ - researcher
21
+ ---
22
+
23
+ # Wiki Query
24
+
25
+ Read a vault (`<project>/.crewly/wiki/`, `~/.crewly/teams/<id>/wiki/`, or `~/.crewly/global-wiki/`) and get back the structured context the caller's LLM uses for synthesis.
26
+
27
+ Per Atlas v2.1 §3, this skill **does not call an LLM itself**. It emits the LLM-agnostic system-context (vault SCHEMA, recent log entries, candidate pages by keyword overlap). The caller's runtime concatenates this with the per-LLM task-instruction prompt at `prompts/<runtime>.md` and makes the LLM call locally.
28
+
29
+ ## When to use
30
+
31
+ - ORC assembling cross-team context for a planning turn.
32
+ - TL pulling the team's last 20 decisions for a sprint review.
33
+ - A worker checking "did we already record an opinion on X?" before writing one.
34
+
35
+ ## Inputs
36
+
37
+ | Flag | Required | Description |
38
+ |---|---|---|
39
+ | `--vault <path>` | yes | Absolute path to a vault root (must contain `SCHEMA.md`). |
40
+ | `--query <text>` | yes | Natural-language question. Used for keyword-overlap candidate ranking. |
41
+ | `--top-k <n>` | no | How many candidate pages to return (default 5). |
42
+ | `--recent-log <n>` | no | How many tail log entries to include (default 20). |
43
+ | `--json <obj>` | alt | Pass all fields as JSON. |
44
+
45
+ ## Output
46
+
47
+ JSON with `success`, `result.context`. The context has:
48
+
49
+ - `vault` — scope, id, absolute path
50
+ - `schemaSummary` — frozen folders, llm-curated layout, write_policy
51
+ - `recentLog` — last N entries (most-recent first), with timestamp / sourceType / caller / body
52
+ - `candidatePages` — top-K pages by keyword overlap with `query`
53
+ - `callerNotes` — synthesis hints the LLM should honor (e.g. refuse writes into frozen paths)
54
+
55
+ ## Example
56
+
57
+ ```bash
58
+ bash execute.sh \
59
+ --vault ~/Desktop/projects/crewly-projects/crewly/.crewly/wiki \
60
+ --query "what did we decide about Crewly Pro pricing in May"
61
+ ```
62
+
63
+ ## Failure modes
64
+
65
+ - `400 invalid_input` — missing vault/query or bad topK
66
+ - `404 schema_missing` — vault has no SCHEMA.md
@@ -0,0 +1,107 @@
1
+ #!/bin/bash
2
+ # wiki-query — fetch a vault's system-context payload for LLM synthesis.
3
+ #
4
+ # Per Atlas v2.1 §3: this skill emits ONLY the system-context (LLM-agnostic).
5
+ # The caller's runtime concatenates this with its per-LLM task-instruction
6
+ # at prompts/<runtime>.md before making the LLM call. The skill itself
7
+ # never curls an LLM endpoint.
8
+ #
9
+ # Usage:
10
+ # bash execute.sh --vault /path/to/vault --query "what did we decide about pricing"
11
+ # bash execute.sh --vault /path/to/vault --query "..." --top-k 10
12
+ # bash execute.sh --json '{"vaultPath":"/path","query":"...","topK":5}'
13
+ # cat input.json | bash execute.sh
14
+ set -euo pipefail
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ source "${SCRIPT_DIR}/../../_common/lib.sh"
17
+
18
+ INPUT_JSON=""
19
+ VAULT_PATH=""
20
+ QUERY=""
21
+ TOP_K=""
22
+ RECENT_LOG=""
23
+
24
+ # Detect legacy JSON positional arg
25
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
26
+ INPUT_JSON="$1"
27
+ shift || true
28
+ fi
29
+
30
+ while [[ $# -gt 0 ]]; do
31
+ case "$1" in
32
+ --vault|-v)
33
+ VAULT_PATH="$2"
34
+ shift 2
35
+ ;;
36
+ --query|-q)
37
+ QUERY="$2"
38
+ shift 2
39
+ ;;
40
+ --top-k|-k)
41
+ TOP_K="$2"
42
+ shift 2
43
+ ;;
44
+ --recent-log|-r)
45
+ RECENT_LOG="$2"
46
+ shift 2
47
+ ;;
48
+ --json|-j)
49
+ INPUT_JSON="$2"
50
+ shift 2
51
+ ;;
52
+ --help|-h)
53
+ cat <<EOF
54
+ Usage:
55
+ execute.sh --vault <vault-dir> --query "<question>" [--top-k 5] [--recent-log 20]
56
+ execute.sh --json '{"vaultPath":"...","query":"...","topK":5,"recentLogEntries":20}'
57
+
58
+ Outputs JSON system-context for the caller's LLM. Skill makes no LLM calls itself.
59
+ EOF
60
+ exit 0
61
+ ;;
62
+ --)
63
+ shift
64
+ break
65
+ ;;
66
+ *)
67
+ if [[ -z "$INPUT_JSON" && ${1:0:1} == '{' ]]; then
68
+ INPUT_JSON="$1"
69
+ shift
70
+ else
71
+ error_exit "Unknown argument: $1"
72
+ fi
73
+ ;;
74
+ esac
75
+ done
76
+
77
+ # Read JSON from stdin if no other input
78
+ if [ -z "$INPUT_JSON" ] && [ -z "$QUERY" ] && [ ! -t 0 ]; then
79
+ STDIN_DATA="$(cat)"
80
+ if [[ ${STDIN_DATA:0:1} == '{' ]]; then
81
+ INPUT_JSON="$STDIN_DATA"
82
+ else
83
+ QUERY="$STDIN_DATA"
84
+ fi
85
+ fi
86
+
87
+ # Parse JSON if supplied
88
+ if [ -n "$INPUT_JSON" ]; then
89
+ INPUT=$(read_json_input "$INPUT_JSON")
90
+ [ -z "$VAULT_PATH" ] && VAULT_PATH=$(printf '%s' "$INPUT" | jq -r '.vaultPath // empty')
91
+ [ -z "$QUERY" ] && QUERY=$(printf '%s' "$INPUT" | jq -r '.query // empty')
92
+ [ -z "$TOP_K" ] && TOP_K=$(printf '%s' "$INPUT" | jq -r '.topK // empty')
93
+ [ -z "$RECENT_LOG" ] && RECENT_LOG=$(printf '%s' "$INPUT" | jq -r '.recentLogEntries // empty')
94
+ fi
95
+
96
+ require_param "vaultPath (--vault)" "$VAULT_PATH"
97
+ require_param "query (--query)" "$QUERY"
98
+
99
+ # Build body with env-var passthrough so jq escapes safely.
100
+ export _WQ_VAULT="$VAULT_PATH"
101
+ export _WQ_QUERY="$QUERY"
102
+ BODY=$(jq -n '{vaultPath: env._WQ_VAULT, query: env._WQ_QUERY}')
103
+ [ -n "$TOP_K" ] && BODY=$(echo "$BODY" | jq --argjson k "$TOP_K" '. + {topK: $k}')
104
+ [ -n "$RECENT_LOG" ] && BODY=$(echo "$BODY" | jq --argjson n "$RECENT_LOG" '. + {recentLogEntries: $n}')
105
+ unset _WQ_VAULT _WQ_QUERY
106
+
107
+ api_call POST "/wiki/query" "$BODY"
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: Wiki Bookkeep
3
+ description: Vault health report — md counts, duplicate clusters, queue snapshot, consolidation recommendations. Returns signals; your LLM decides what to merge or archive.
4
+ version: 1.0.0
5
+ category: knowledge
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ - team-leader
10
+ ---
11
+
12
+ # Wiki Bookkeep
13
+
14
+ Periodic vault health check. Returns a structured report (md counts, recent activity, duplicate clusters by filename similarity, stale-page count, queue snapshot, recommendations). **The skill does not write to the vault.** Your LLM reads the report and decides next actions.
15
+
16
+ ## When to use
17
+
18
+ - When `wiki-process-queue` returns `no_pending_items` — quiet moment, good for housekeeping.
19
+ - When the report's `shouldFire` was `true` on the last run (you owe the vault a consolidation pass).
20
+ - When you receive a `[BOOKKEEP] vault=…` message (a future cron + threshold trigger will deliver these).
21
+
22
+ ## Inputs
23
+
24
+ | Flag | Required | Default | Description |
25
+ |---|---|---|---|
26
+ | `--vault <path>` | yes | — | Absolute vault path. |
27
+ | `--window-days <n>` | no | 7 | "Recent activity" window for `recentMdCount`. |
28
+ | `--threshold <n>` | no | 10 | `shouldFire` triggers when `recentMdCount >= threshold` OR there are duplicate clusters. |
29
+
30
+ ## What you do with the report
31
+
32
+ 1. **Drain pending queue first** — if `queue.pending > 0`, run `wiki-process-queue` until empty before doing anything else.
33
+ 2. **Consolidate duplicate clusters** — for each cluster in `duplicateCandidates`, read the member pages, ask your LLM whether they should merge, and if yes:
34
+ - Call `wiki-ingest` with a consolidated body that supersedes the originals (preserve the most-load-bearing info, deduplicate restated facts).
35
+ - Note: page DELETION is not in Phase 1 — surface "these N old pages can be archived" in your reply for human review.
36
+ 3. **Hot-folder rollups** — if `countsByFolder` shows >20 pages in one bucket without a recent index page, generate one. Pattern: `llm-curated/<folder>/index.md` linking + summarizing each page.
37
+ 4. **Stale-page flag** — if `staleCount > 0`, mention to the user — they decide which to keep.
38
+
39
+ ## Output
40
+
41
+ ```json
42
+ {
43
+ "success": true,
44
+ "report": {
45
+ "vault": {"scope": "project", "id": "crewly", "path": "..."},
46
+ "generatedAt": "2026-05-23T03:00:00Z",
47
+ "windowDays": 7,
48
+ "threshold": 10,
49
+ "shouldFire": true,
50
+ "totalMdCount": 47,
51
+ "recentMdCount": 12,
52
+ "countsByFolder": {"llm-curated/decisions": 8, "llm-curated/customers": 3, ...},
53
+ "duplicateCandidates": [
54
+ {"basis": "llm-curated/customers/anthropic-pricing", "pages": ["...-v1.md", "...-v2.md"]}
55
+ ],
56
+ "staleCount": 4,
57
+ "queue": {"pending": 2, "claimed": 0, "processed": 11, "skipped": 1, "total": 14},
58
+ "recommendations": [
59
+ "Window has 12 new md(s) — at or above threshold (10). Consider a consolidation pass.",
60
+ "1 likely-duplicate cluster(s) detected. ...",
61
+ ...
62
+ ]
63
+ }
64
+ }
65
+ ```
66
+
67
+ ## Failure modes
68
+
69
+ - `404 vault_missing` — the vault directory does not exist.
70
+ - `404 schema_missing` — vault has no SCHEMA.md.
71
+ - `400 invalid_input` — vaultPath not absolute / windowDays or threshold non-positive.
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+ # wiki-bookkeep — vault health report + consolidation signals.
3
+ #
4
+ # Use this skill periodically (or when the queue stats / md-count
5
+ # threshold says "fire"). The skill returns a JSON report:
6
+ # - total / recent md counts
7
+ # - per-folder bucket counts
8
+ # - likely-duplicate clusters (filename Jaccard)
9
+ # - stale-page count (90+ days untouched)
10
+ # - queue snapshot (pending/claimed/processed/skipped)
11
+ # - recommendations
12
+ #
13
+ # This skill does NOT write to the vault. After reading the report,
14
+ # YOUR runtime decides which clusters to merge (call wiki-ingest with
15
+ # a consolidated body) and which pages to archive (out of Phase 1
16
+ # scope — flag in chat for now).
17
+ #
18
+ # Usage:
19
+ # bash execute.sh --vault /path
20
+ # bash execute.sh --vault /path --window-days 14 --threshold 10
21
+ set -euo pipefail
22
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ source "${SCRIPT_DIR}/../../_common/lib.sh"
24
+
25
+ INPUT_JSON=""
26
+ VAULT_PATH=""
27
+ WINDOW=""
28
+ THRESHOLD=""
29
+
30
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
31
+ INPUT_JSON="$1"; shift || true
32
+ fi
33
+
34
+ while [[ $# -gt 0 ]]; do
35
+ case "$1" in
36
+ --vault|-v) VAULT_PATH="$2"; shift 2 ;;
37
+ --window-days|-d) WINDOW="$2"; shift 2 ;;
38
+ --threshold|-t) THRESHOLD="$2"; shift 2 ;;
39
+ --json|-j) INPUT_JSON="$2"; shift 2 ;;
40
+ --help|-h)
41
+ cat <<EOF
42
+ Usage:
43
+ execute.sh --vault <path> [--window-days 7] [--threshold 10]
44
+
45
+ Returns a JSON bookkeeping report with should-fire signal, recent activity,
46
+ duplicate clusters, queue snapshot, and recommendations. The skill makes
47
+ no LLM calls; you decide next actions based on the report.
48
+ EOF
49
+ exit 0 ;;
50
+ --) shift; break ;;
51
+ *)
52
+ if [[ -z "$INPUT_JSON" && ${1:0:1} == '{' ]]; then INPUT_JSON="$1"; shift
53
+ else error_exit "Unknown argument: $1"; fi ;;
54
+ esac
55
+ done
56
+
57
+ if [ -n "$INPUT_JSON" ]; then
58
+ INPUT=$(read_json_input "$INPUT_JSON")
59
+ [ -z "$VAULT_PATH" ] && VAULT_PATH=$(printf '%s' "$INPUT" | jq -r '.vaultPath // empty')
60
+ [ -z "$WINDOW" ] && WINDOW=$(printf '%s' "$INPUT" | jq -r '.windowDays // empty')
61
+ [ -z "$THRESHOLD" ] && THRESHOLD=$(printf '%s' "$INPUT" | jq -r '.threshold // empty')
62
+ fi
63
+
64
+ require_param "vaultPath (--vault)" "$VAULT_PATH"
65
+
66
+ export _WB_V="$VAULT_PATH"
67
+ BODY=$(jq -n '{vaultPath: env._WB_V}')
68
+ [ -n "$WINDOW" ] && BODY=$(echo "$BODY" | jq --argjson w "$WINDOW" '. + {windowDays: $w}')
69
+ [ -n "$THRESHOLD" ] && BODY=$(echo "$BODY" | jq --argjson t "$THRESHOLD" '. + {threshold: $t}')
70
+ unset _WB_V
71
+
72
+ api_call POST "/wiki/bookkeep" "$BODY"
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: Wiki Ingest
3
+ description: Append a source (spec / decision / chat / pr / learning) into a vault's llm-curated/ tree. Refuses writes into frozen paths.
4
+ version: 1.0.0
5
+ category: knowledge
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ - team-leader
10
+ ---
11
+
12
+ # Wiki Ingest
13
+
14
+ Append a source to a vault's `llm-curated/log.md` (default) or to a dedicated page under `llm-curated/` (via `--target`). Per Atlas v2.1 §2 + §3.
15
+
16
+ The chat subscriber **already** auto-ingests every user→ORC chat message; this skill is for explicit manual ingest:
17
+
18
+ - TL promoting a decision to `llm-curated/decisions/<date>-<slug>.md`
19
+ - ORC archiving a synthesis memo into `~/.crewly/global-wiki/llm-curated/`
20
+ - A worker filing a `record-learning`-style pattern page
21
+
22
+ ## Inputs
23
+
24
+ | Flag | Required | Description |
25
+ |---|---|---|
26
+ | `--vault <path>` | yes | Absolute vault root (must contain `SCHEMA.md`). |
27
+ | `--source-type <t>` | yes | One of: `user_chat`, `slack_message`, `spec_file`, `pr_merge`, `record_learning`, `task_verified`. |
28
+ | `--source-ref <ref>` | yes | Stable reference for audit (URL, file path, message id, …). |
29
+ | `--source-body <text>` | yes | Body content to ingest. |
30
+ | `--caller <sess>` | no | Session/user that authored the source (defaults to source-ref). |
31
+ | `--target <relpath>` | no | Override the default `llm-curated/log.md`. Must NOT be inside a frozen folder. |
32
+
33
+ ## Output
34
+
35
+ ```json
36
+ {
37
+ "success": true,
38
+ "result": {
39
+ "ok": true,
40
+ "pagesWritten": ["llm-curated/log.md"],
41
+ "logEntry": "## [ISO] sourceType | caller ...",
42
+ "frozenPathsTouched": []
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Failure modes
48
+
49
+ - `422 frozen_path` — target lives under a `hardcoded:` (frozen) folder. The `outcome.frozenFolders` field lists every frozen path in the vault.
50
+ - `404 schema_missing` — vault has no `SCHEMA.md`.
51
+ - `400 invalid_input | empty_body` — missing/invalid args.
52
+
53
+ ## Example: ingest a TL-promoted decision
54
+
55
+ ```bash
56
+ bash execute.sh \
57
+ --vault ~/.crewly/teams/ad923b66-19dd-4d73-9c92-dc1107d37501/wiki \
58
+ --source-type user_chat \
59
+ --source-ref slack://thread/D0ABC/1779363330.313849 \
60
+ --source-body "Pricing locked at \$999 setup + \$799/month." \
61
+ --caller user/steve \
62
+ --target llm-curated/decisions/2026-05-22-crewly-pro-pricing.md
63
+ ```