shraga 0.1.13 → 0.1.15

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 (55) hide show
  1. package/defaults/modules/routine/README.md +38 -0
  2. package/defaults/modules/routine/module.json +36 -0
  3. package/defaults/modules/routine/routine.md.tmpl +75 -0
  4. package/defaults/modules/routine/seeds/workspace/agenda.md +15 -0
  5. package/defaults/skills/add-skill.md +4 -0
  6. package/defaults/skills/artifacts.md +4 -0
  7. package/defaults/skills/communications.md +4 -0
  8. package/defaults/skills/create-module.md +75 -0
  9. package/defaults/skills/debug.md +4 -0
  10. package/defaults/skills/garden.md +4 -0
  11. package/defaults/skills/github-contributor.md +4 -0
  12. package/defaults/skills/identity.md +4 -0
  13. package/defaults/skills/mcp-server.md +4 -0
  14. package/defaults/skills/modules.md +41 -0
  15. package/defaults/skills/plan.md +4 -0
  16. package/defaults/skills/reconcile.md +4 -0
  17. package/defaults/skills/scheduler.md +5 -2
  18. package/defaults/skills/self-aware.md +5 -1
  19. package/defaults/skills/write-tests.md +4 -0
  20. package/dist/client/assets/index-D5KxKl57.js +1946 -0
  21. package/dist/client/assets/index-nyZagTjP.css +10 -0
  22. package/dist/client/index.html +2 -2
  23. package/package.json +1 -1
  24. package/src/client/App.tsx +11 -0
  25. package/src/client/components/ChatView.tsx +14 -0
  26. package/src/client/components/ConversationHeader.tsx +29 -0
  27. package/src/client/components/ModulesManager.tsx +259 -0
  28. package/src/client/hooks/useConversation.ts +5 -3
  29. package/src/client/hooks/useModules.ts +81 -0
  30. package/src/client/lib/api.ts +13 -0
  31. package/src/client/lib/sessionApi.ts +16 -2
  32. package/src/client/lib/workspaceContext.tsx +2 -0
  33. package/src/mcp-stdio-bridge.ts +5 -5
  34. package/src/server/boot.ts +95 -16
  35. package/src/server/claude.ts +12 -1
  36. package/src/server/data-sync.ts +28 -0
  37. package/src/server/engine/claude-code.ts +10 -3
  38. package/src/server/events/types.ts +3 -0
  39. package/src/server/mcp-sidecar.ts +2 -2
  40. package/src/server/mcp.ts +3 -5
  41. package/src/server/modules/index.ts +3 -0
  42. package/src/server/modules/routes.ts +78 -0
  43. package/src/server/modules/service.ts +575 -0
  44. package/src/server/modules/types.ts +62 -0
  45. package/src/server/paths.ts +57 -6
  46. package/src/server/scheduler/builtins.ts +27 -3
  47. package/src/server/scheduler/engine.ts +6 -0
  48. package/src/server/scheduler/runner.ts +96 -30
  49. package/src/server/scheduler/types.ts +3 -0
  50. package/src/server/sessions.ts +4 -0
  51. package/src/server/shraga-config.ts +21 -4
  52. package/src/server/skills.ts +6 -5
  53. package/src/server/slack/bot.ts +3 -1
  54. package/dist/client/assets/index-ChElotX8.js +0 -1936
  55. package/dist/client/assets/index-DdibEb2O.css +0 -10
@@ -0,0 +1,38 @@
1
+ # routine
2
+
3
+ Turns the agent into a self-driving daily operator: a rendered `routine` skill (the operating contract — hours, OKR-anchored priority function, tick logic, autonomy tiers, comms policy), two schedules, and a seeded `workspace/agenda.md` the dispatcher uses as working memory.
4
+
5
+ ## What installs
6
+
7
+ - **Skill** `skills/routine.md` — rendered from the template with your config.
8
+ - **Schedule** `routine-tick` (enabled) — hourly dispatcher tick during work hours; most ticks end in a skip.
9
+ - **Schedule** `routine-work-block` (**ships disabled**) — a superseded midday fallback; enable only if you want a guaranteed daily work block instead of tick-driven cadence.
10
+ - **Seed** `workspace/agenda.md` — created only if missing; never overwritten.
11
+
12
+ ## Config
13
+
14
+ | Key | Default | Meaning |
15
+ |---|---|---|
16
+ | `workingDays` | `Sun–Thu` | Working days (prose, shown in the skill) |
17
+ | `workHours` | `08:00–18:00` | Working hours (prose) |
18
+ | `tz` | `Asia/Jerusalem` | IANA timezone for schedules and hours |
19
+ | `tickCron` | `0 8-17 * * 0-4` | Dispatcher tick cron — keep inside work hours |
20
+ | `tickModel` | `haiku` | Model for the dispatcher tick — keeps ticks on a cheap model |
21
+ | `maxSelfWakesPerDay` | `4` | Max agent-booked `self-wake-*` continuations per day |
22
+ | `workBlockCron` | `0 12 * * 0-4` | Fallback work-block cron (schedule ships disabled) |
23
+ | `okrSource` | `okrs/q3-2026-draft.md` | Data-relative OKR doc anchoring the priority function |
24
+ | `channel` | `#agf-dev` | Primary comms channel once past pilot |
25
+ | `ownerName` | `Elya` | Human owner all pilot-mode comms route to |
26
+ | `pilotMode` | `true` | `true` = no team tagging, everything to the owner; `false` = channel-first threaded comms |
27
+
28
+ Changing config re-renders the skill and schedules (`PUT /api/modules/routine/config`).
29
+
30
+ Note: adopted/managed schedules become `scope: system` — their sessions are visible to all whitelisted users (team-transparency doctrine).
31
+
32
+ ## Offspring
33
+
34
+ Agent-booked continuations matching `self-wake-*` are treated as the module's offspring: disabling or uninstalling the module disables them (never deletes) so they can't fire into a missing skill.
35
+
36
+ ## Uninstall semantics
37
+
38
+ Rendered skill and the two module schedules are removed. **State stays**: `workspace/agenda.md` (and any board/log files the doctrine produced) are memory, not status — they remain on disk with a dormancy header. Only `data/modules/state.json` answers whether the module is on.
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "routine",
3
+ "version": "1.1.0",
4
+ "description": "Daily operating contract — cadence (dispatcher ticks + work blocks), OKR-anchored priorities, autonomy tiers, comms policy, and an agenda seed.",
5
+ "configSchema": {
6
+ "workingDays": { "type": "string", "default": "Sun–Thu", "description": "Working days, prose (shown in the skill)" },
7
+ "workHours": { "type": "string", "default": "08:00–18:00", "description": "Working hours, prose (shown in the skill)" },
8
+ "tz": { "type": "string", "default": "Asia/Jerusalem", "description": "IANA timezone for schedules and hours" },
9
+ "tickCron": { "type": "string", "default": "0 8-17 * * 0-4", "description": "Cron for the hourly dispatcher tick (keep inside work hours)" },
10
+ "tickModel": { "type": "string", "default": "haiku", "description": "Model for the dispatcher tick — keeps ticks on a cheap model (most end in a skip)" },
11
+ "maxSelfWakesPerDay": { "type": "number", "default": 4, "description": "Max agent-booked self-wake-* continuations per day" },
12
+ "workBlockCron": { "type": "string", "default": "0 12 * * 0-4", "description": "Cron for the fallback work block (schedule ships disabled)" },
13
+ "okrSource": { "type": "string", "default": "okrs/q3-2026-draft.md","description": "Data-relative path to the OKR doc anchoring priorities" },
14
+ "channel": { "type": "string", "default": "#agf-dev", "description": "Primary comms channel once past pilot" },
15
+ "ownerName": { "type": "string", "default": "Elya", "description": "The human owner all pilot-mode comms route to" },
16
+ "pilotMode": { "type": "boolean", "default": true, "description": "true = no team tagging, everything routes to the owner; false = channel-first threaded comms" }
17
+ },
18
+ "skills": ["routine.md.tmpl"],
19
+ "schedules": [
20
+ {
21
+ "def": "tick",
22
+ "name": "routine-tick",
23
+ "trigger": { "kind": "cron", "expr": "{{tickCron}}", "tz": "{{tz}}" },
24
+ "task": { "kind": "prompt", "prompt": "Dispatcher tick: load the routine skill (Dispatcher tick rules) and workspace/agenda.md, then follow the tick logic. Most ticks should end in a skip.", "model": "{{tickModel}}" }
25
+ },
26
+ {
27
+ "def": "work-block",
28
+ "name": "routine-work-block",
29
+ "enabled": false,
30
+ "trigger": { "kind": "cron", "expr": "{{workBlockCron}}", "tz": "{{tz}}" },
31
+ "task": { "kind": "prompt", "prompt": "Load the routine skill and execute one work block per its Cadence section." }
32
+ }
33
+ ],
34
+ "seeds": ["workspace/agenda.md"],
35
+ "offspring": { "schedules": "self-wake-*" }
36
+ }
@@ -0,0 +1,75 @@
1
+ ---
2
+ description: My daily operating contract — cadence, priorities (OKR-anchored), autonomy tiers, comms policy. Loaded by the dispatcher tick and work-block schedules; consult it before any proactive move.
3
+ triggers:
4
+ - routine
5
+ - dispatcher tick
6
+ - work block
7
+ - daily cadence
8
+ - what should I work on
9
+ ---
10
+
11
+ My standing contract for proactive work. Config: `pilotMode={{pilotMode}}`, owner {{ownerName}}, channel {{channel}}.
12
+
13
+ ## Working hours
14
+
15
+ {{workingDays}}, roughly {{workHours}} ({{tz}}). Outside these hours: no proactive work, no pings — only respond if directly addressed. Exemption: event-triggered reactions (an incoming webhook, alert, or message that fires a schedule/session) may be handled when they arrive — the hours gate self-initiated work, not reactions.
16
+
17
+ ## Priority function
18
+
19
+ When choosing what to pick up, rank by:
20
+ 1. **Moves a KR** — anchored in `{{okrSource}}` and the Weekly Log. Tasks tagged `KR:` outrank everything else.
21
+ 2. **Urgency** — P0/P1 items next.
22
+ 3. **Age** — older items before newer, all else equal.
23
+
24
+ ## Cadence
25
+
26
+ - **Pre-daily** (start of day): absorbs the morning sweep — review inboxes/boards, refresh `workspace/agenda.md` (Today/Focus/Queue), pick the day's focus.
27
+ - **Dispatcher tick** (hourly during work hours) — the tick decides, it does not grind:
28
+ - **Skip** if a session is already actively working — most ticks should end in a skip.
29
+ - **Defer to self-wake**: if a `self-wake-*` schedule is already booked for the current thread, skip — the wake owns the continuation.
30
+ - **Wake with intention**: only start work when the agenda names a concrete next step; wake into that step, not into "look around".
31
+ - **Escalate when stuck**: the same item blocked across 3 consecutive ticks → escalate per the comms policy instead of ticking on it again.
32
+ - **Post-daily** (end of day): absorbs the EOD digest — summarize what moved, update the agenda's Parked/Blocked, leave breadcrumbs.
33
+ - **Weekly self-audit**: once a week, review the log against `{{okrSource}}` — is the priority function actually being followed?
34
+
35
+ The `routine-work-block` schedule is a superseded fallback (ships disabled); the tick logic above is the live cadence.
36
+
37
+ ## Self-scheduling
38
+
39
+ I MAY book my own continuations as one-shot schedules (`once` trigger) named `self-wake-<slug>`. Bounds:
40
+ - tier-a work only — never self-wake into tier b/c actions;
41
+ - working hours only;
42
+ - max {{maxSelfWakesPerDay}} self-wakes per day;
43
+ - each booking notes "why then" in `workspace/agenda.md` (what the wake will do and why that time).
44
+
45
+ ## Breadcrumb contract
46
+
47
+ Every pause or handoff ends with a `Next:` line stating the concrete next step. A thread without a `Next:` line is not parked, it is dropped.
48
+
49
+ ## Autonomy tiers
50
+
51
+ - **a** — reversible + verifiable: do it, report after.
52
+ - **b** — hard to reverse or externally visible: propose, wait for approval.
53
+ - **c** — irreversible / spend / identity-affecting: never without an explicit go in the current session.
54
+
55
+ The tier is decided by reversibility, not by confidence.
56
+
57
+ ## Comms policy
58
+
59
+ Pilot restriction active: **{{pilotMode}}**.
60
+ - When `true`: do NOT tag or ping team members — every outbound update, question, and escalation routes to {{ownerName}} only.
61
+ - When `false`: channel-first — post threaded updates in {{channel}}; tag people only when they own the next action.
62
+
63
+ Signal tiers (either mode): **ping** = needs a human now; **digest** = batched into pre/post-daily summaries; **board** = silent state update on the agenda/board only. Unsure which tier → digest; batch same-class nudges into one line.
64
+
65
+ ## Loop-in while uncertain
66
+
67
+ Uncertainty is not a reason to stall silently: keep working what is safe (tier a), and loop in {{ownerName}} on the uncertain part in the same breath — ask while moving, never block-and-vanish.
68
+
69
+ The moment a finding rules out a previously stated theory (mine or a teammate's) on an open P0/P1, surface it to the owner of that item in the same session, unpolished, before chasing the next hypothesis. (Pilot mode: the owner to loop in is {{ownerName}}.)
70
+
71
+ ## agenda.md scoping
72
+
73
+ `workspace/agenda.md` is the dispatcher's working memory, NOT the board — `tasks/tasks.md` is the durable record. The agenda points at tasks; it never replaces them.
74
+ - **Read** it only on proactive turns (ticks, pre/post-daily) — a user-initiated turn follows the user, not the agenda.
75
+ - **Write** it on any turn where state changed (new task, decision, block, park).
@@ -0,0 +1,15 @@
1
+ # Agenda
2
+
3
+ <!-- Dispatcher working memory (routine module). Read on proactive turns only; write whenever state changes. -->
4
+
5
+ ## Today
6
+
7
+ ## Focus
8
+
9
+ ## Queue
10
+
11
+ ## Decisions
12
+
13
+ ## Parked
14
+
15
+ ## Blocked
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: How to add a new skill — create a kebab-case Markdown file in the absolute data/skills/ path with concise system-prompt-style instructions.
3
+ ---
4
+
1
5
  To add a new skill, create a Markdown file in the **absolute path** `<shraga folder>/data/skills/`:
2
6
 
3
7
  1. **File**: Create `<shraga folder>/data/skills/<skill-name>.md` using kebab-case naming (e.g. `code-review.md`, `write-tests.md`)
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Create and iterate on self-contained visual HTML artifacts (ad creatives, banners, cards) that render live in the user's browser.
3
+ ---
4
+
1
5
  # Artifacts — HTML Creative Builder
2
6
 
3
7
  You can create and iterate on visual HTML artifacts (ad creatives, banners, cards, etc.) that render live in the user's browser.
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Maintain the communications log (data/comms-log.jsonl) to avoid duplicate or redundant proactive outreach.
3
+ ---
4
+
1
5
  # Communications Awareness
2
6
 
3
7
  You maintain a communications log to avoid duplicate or redundant **proactive** outreach. Scheduled reports and user-requested messages are always fine to send — dedup only applies to agent-initiated messages.
@@ -0,0 +1,75 @@
1
+ ---
2
+ description: Author a data-plane module — a declarative folder (module.json + skill templates + schedules + seeds) that shraga installs, configures, and toggles at runtime. Covers the manifest contract, {{key}} templating, skills-vs-seeds semantics, and the propose-then-approve workflow.
3
+ triggers:
4
+ - create a module
5
+ - author a module
6
+ - new module
7
+ - module manifest
8
+ - module.json
9
+ - package a skill as a module
10
+ - data-plane module
11
+ ---
12
+
13
+ A **data-plane module** is a declarative folder of skills, schedules, and seed files that shraga installs and reconciles at runtime — no server code. Use it to package a behavior (skill + cadence + state files) so it can be installed, configured, enabled/disabled, and upgraded as one unit.
14
+
15
+ Not a module: `*.ext.ts` extensions and `registerFeature` features are **server-plane code** (routes, hooks, services). If the behavior needs code, it's not a module.
16
+
17
+ ## Manifest — `module.json`
18
+
19
+ ```json
20
+ {
21
+ "name": "standup-notes",
22
+ "version": "1.0.0",
23
+ "description": "Collects a daily standup note and keeps a rolling log.",
24
+ "configSchema": {
25
+ "tz": { "type": "string", "default": "UTC", "description": "Timezone" },
26
+ "channel": { "type": "string", "default": "", "description": "Where to post the note" }
27
+ },
28
+ "skills": ["standup-notes.md.tmpl"],
29
+ "schedules": [
30
+ { "def": "tick", "name": "standup-notes tick",
31
+ "trigger": { "kind": "cron", "expr": "30 9 * * 1-5", "tz": "{{tz}}" },
32
+ "task": { "kind": "prompt", "prompt": "Run the standup-notes skill: collect today's note, post to {{channel}}, append to the log." } }
33
+ ],
34
+ "seeds": ["workspace/standup-log.md"],
35
+ "offspring": { "schedules": "standup-followup-*" },
36
+ "defaultSkills": []
37
+ }
38
+ ```
39
+
40
+ - `configSchema` — flat map of `{type, default, description}`. Values are user-editable via the modules UI / `PUT /api/modules/:name/config`; every change re-renders.
41
+ - `skills` — `.md.tmpl` files rendered into `data/skills/<name>.md` with a `managed-by: <module>@<version>` frontmatter marker.
42
+ - `schedules` — schedule defs keyed by a stable `def` (→ schedule id `mod-<module>-<def>`), using the scheduler's native `trigger`/`task` JSON (same shape as `POST /api/schedules` — see the scheduler skill), with `{{key}}` substitution in string values; created with `managedBy`, survive reboots, stay user-editable (reconcile re-overwrites trigger/task but preserves enabled/runCount). `"enabled": false` on a def ships it off on first install (a superseded fallback, say) without forcing it off later.
43
+ - **Adoption/reconcile replaces `trigger`+`task` WHOLLY from the def** — any hand-customized field on an existing schedule (a `model` override, a tweaked prompt) will be lost unless it becomes a config knob referenced by the def (e.g. `"model": "{{tickModel}}"` in the `routine` builtin). A `model` knob rendered to `""` is omitted from the schedule (no bogus empty model).
44
+ - Adopted/managed schedules become `scope: system` — their sessions are visible to all whitelisted users (intended: team transparency).
45
+ - `seeds` — files created data-root-relative if missing (e.g. `workspace/standup-log.md`).
46
+ - `offspring.schedules` — glob matching schedules the *agent* creates while following the module's skill (e.g. self-booked follow-ups). Disabling the module also disables them.
47
+ - `defaultSkills` — module skill names to add to the always-inject list (use sparingly; most skills are on-demand).
48
+
49
+ ## `{{key}}` templating
50
+
51
+ Any string in skill templates and schedule defs may reference a config key as `{{key}}`. Plain substitution only — **no conditionals or logic**, unknown keys warn. Rendering happens at install, config change, and upgrade.
52
+
53
+ Branching on a boolean knob: since there are no template conditionals, interpolate the value into a doctrine line and let prose tell the agent how to behave for each value — e.g. `Pilot restriction active: **{{pilotMode}}**.` followed by "When `true`: … / When `false`: …" (see the `routine` builtin).
54
+
55
+ ## Semantics — skills vs seeds vs offspring
56
+
57
+ | Kind | Nature | On reconcile/upgrade | On disable | On uninstall |
58
+ |---|---|---|---|---|
59
+ | skills | code | overwritten from template | deleted | deleted |
60
+ | schedules (declared) | code | upserted (enabled/runCount preserved) | disabled (snapshot restored on enable) | deleted |
61
+ | seeds | state | **never overwritten** | dormancy header stamped, removed on re-enable | **left in place** |
62
+ | offspring schedules | agent-created | untouched | disabled, never deleted | disabled, never deleted |
63
+
64
+ Seeds are memory, not status — never encode "is the module on" in a seed file; only `data/modules/state.json` answers that.
65
+
66
+ ## Authoring workflow
67
+
68
+ 1. Scaffold in `workspace/modules-dev/<name>/` — `module.json` + templates + seed files. Keep the skill under ~15 lines, direct-instruction tone (see the add-skill skill).
69
+ 2. Validate: manifest parses, every `{{key}}` exists in `configSchema`, schedule crons are sane.
70
+ 3. Install: `curl -s -X POST -H "x-internal-token: $INTERNAL_API_TOKEN" http://localhost:$PORT/api/modules/install -d '{"path":"workspace/modules-dev/<name>"}' -H 'content-type: application/json'`
71
+ 4. Iterate: edit source → re-install; tune values via `PUT /api/modules/:name/config` (triggers reconcile).
72
+
73
+ ## Agent rule — propose, never self-install
74
+
75
+ You may **author** a module folder and present it (folder path + one-paragraph summary of what it installs and when it fires) — but a **human installs it**. Never call the install endpoint on your own initiative; step 3 above runs only after the owner explicitly approves in-session.
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Systematic debugging workflow — reproduce, hypothesize likely root causes, investigate, isolate the smallest failing case, apply a targeted fix, and verify.
3
+ ---
4
+
1
5
  You are debugging a problem. Follow this systematic approach:
2
6
 
3
7
  1. **Reproduce**: Confirm you understand the exact symptom and when it occurs
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Structural maintenance of the workspace knowledge base — deduplicate, restructure, compress, and cross-reference (run before reconcile).
3
+ ---
4
+
1
5
  # Knowledge Gardening
2
6
 
3
7
  You are performing structural maintenance on the workspace knowledge base — deduplicating, restructuring, compressing, and cross-referencing. Think of this as defragmenting the team's shared memory: same information, better organized.
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Act as an autonomous GitHub contributor — handle issues/PRs arriving via webhook, honoring trust tiers (autonomous/gated) that gate implement, verify, and merge.
3
+ ---
4
+
1
5
  # GitHub Contributor
2
6
 
3
7
  You can act as an autonomous contributor on GitHub repos. Issues and PRs arrive as conversation turns (via the GitHub webhook); your final reply text is posted back as a comment on the thread.
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: The built-in contact registry (data/contacts.json) that tracks operators, owners, and everyone you interact with across channels.
3
+ ---
4
+
1
5
  ## Contact Registry
2
6
 
3
7
  A built-in contact registry at `data/contacts.json` automatically tracks everyone you interact with across all channels.
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: The embedded MCP endpoint (POST /mcp) and uck_ API keys that let external Claude clients access workspace, skills, sessions, schedules, and remote prompts.
3
+ ---
4
+
1
5
  # MCP Server & API Keys
2
6
 
3
7
  Shraga exposes an embedded MCP endpoint at `POST /mcp` so external Claude clients (Claude Desktop, Claude Cloud, other MCP consumers) can access workspace, skills, sessions, schedules, and run prompts remotely.
@@ -0,0 +1,41 @@
1
+ ---
2
+ description: Know which data-plane modules are installed/enabled and manage their lifecycle (enable/disable/configure) via the internal REST API — with the doctrine gate on when you may act vs propose.
3
+ triggers:
4
+ - what modules are enabled
5
+ - what modules are installed
6
+ - module status
7
+ - enable module
8
+ - disable module
9
+ - configure module
10
+ - list modules
11
+ ---
12
+
13
+ Data-plane modules bundle skills + schedules + seed files, installed and reconciled at runtime. Here's how to know what's on and how to change it.
14
+
15
+ ## Knowing what's installed / enabled
16
+
17
+ - **Source of truth**: read `data/modules/state.json` — installed modules with `enabled`, `version`, `config`. Only this file answers "is the module on."
18
+ - **API**: `curl -s -H "x-internal-token: $INTERNAL_API_TOKEN" http://localhost:$PORT/api/modules | jq .` — installed + available built-ins (shipped in `defaults/modules/`, e.g. `routine`; install by `{"name":"routine"}`).
19
+ - **Skill index**: module-rendered skills carry `managed-by: <module>@<version>` frontmatter — if you see it on a skill, a module owns that file.
20
+
21
+ ## How lifecycle changes surface
22
+
23
+ - Enable/disable/install/uninstall appends a line to the workspace journal — trust it as a signal, verify in `state.json`.
24
+ - A disabled module's seed files get a dormancy header (`> [<module> disabled <date> — retained as state; no proactive cadence active]`). **Seeds are memory, not status**: an agenda/log file existing — even without the header — does not mean the module is active. Check `state.json` before acting on any cadence a seed implies.
25
+ - Disabling also disables the module's declared schedules *and* offspring schedules you created under its doctrine — don't re-create them while it's off.
26
+
27
+ ## Managing modules
28
+
29
+ ```bash
30
+ H='-H "x-internal-token: $INTERNAL_API_TOKEN"' # all calls need this header
31
+ # NOTE: mutations are owner-gated — use a SCOPED internal token (carries the owner session).
32
+ # The legacy global token maps to a non-owner identity and gets 403 on everything but GET.
33
+ POST /api/modules/:name/enable | disable
34
+ PUT /api/modules/:name/config # JSON body validated vs configSchema, then reconciled
35
+ POST /api/modules/install # {"name":"<builtin>"} or {"path":"<folder>"}
36
+ DELETE /api/modules/:name # uninstall — seeds stay
37
+ ```
38
+
39
+ **Doctrine gate:**
40
+ - enable / disable / config change — **tier-b**: propose to the owner and wait, *unless* the owner explicitly asked for this change in the current session (then do it and report).
41
+ - install / uninstall — **always** propose-then-approve. Never self-install, even if you authored the module (see create-module skill).
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Produce a concise implementation plan before writing code — goal, approach, steps, files affected, and risks/open questions.
3
+ ---
4
+
1
5
  Before writing any code, produce a concise implementation plan:
2
6
 
3
7
  1. **Goal**: One sentence summary of what we're building
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Workspace knowledge reconciliation — audit what the team knows, learn from recent conversations, and keep the knowledge base clean and current (run garden first).
3
+ ---
4
+
1
5
  # Knowledge Reconciliation
2
6
 
3
7
  You are performing a workspace knowledge reconciliation — auditing what the team knows, learning from recent conversations, and keeping the knowledge base clean and current. Think of this like how the human mind works during sleep: rearranging information, strengthening important connections, discarding noise.
@@ -156,13 +156,15 @@ For **vendor webhooks** that can't send shraga auth (Stripe, GitHub, …), add a
156
156
 
157
157
  The system emits these onto the bus automatically — use them as the `source` of an event trigger to react to the agent's own lifecycle:
158
158
 
159
- - **`schedule.finished`** — fired when any time/manual schedule run completes. Payload: `{ scheduleId, name, status, sessionId, error? }`. `status` is `ok` | `error` | `aborted`. Chain automations off it, e.g.:
159
+ - **`schedule.finished`** — fired when any time/manual schedule run completes. Payload: `{ scheduleId, name, status, sessionId, sessionUrl?, error? }`. `status` is `ok` | `error` | `aborted`. Chain automations off it, e.g.:
160
160
  ```json
161
161
  { "trigger": { "kind": "event", "source": "schedule.finished", "match": { "status": "error" } },
162
162
  "task": { "kind": "prompt", "prompt": "A scheduled run failed — investigate and post a summary." } }
163
163
  ```
164
164
  Runs that were *themselves* event-triggered do NOT emit `schedule.finished` — this prevents feedback loops, so you can't chain `schedule.finished` → event run → `schedule.finished` infinitely.
165
165
 
166
+ A `status: error` on a **prompt** run means it failed up to 3 times, not once: a transient failure that produced no output at all (no token, no tool call — so no side effect) is retried with a short backoff before being reported. So `error` is a real failure worth acting on, not a blip. Job (shell command) runs are never retried — a non-zero exit says nothing about what the command already did.
167
+
166
168
  ## Throttling event triggers
167
169
 
168
170
  Event triggers accept an optional `throttle` that suppresses duplicate fires **before** a run is spawned:
@@ -180,7 +182,8 @@ The dedup key is built from the named payload fields (dot-paths), string-normali
180
182
 
181
183
  1. Enable it (toggle the schedule).
182
184
  2. Optionally set `SHRAGA_ALERT_SLACK_EMAIL` (the legacy `UNCLAW_ALERT_SLACK_EMAIL` is still honoured) (else it falls back to the first `data/whitelist.json` entry).
183
- 3. Optionally edit its `task.prompt` to add deployment specifics (recipients, runbook links, severity rules, base URL)your edits to a builtin's prompt and `enabled` flag survive upgrades; only `name`/`scope`/`createdBy` reconcile from code.
185
+ 3. Set `PUBLIC_ORIGIN` (or `publicOrigin` in the data-dir config) so the alert can link to the failed run's session. It is the only source of a publicly-reachable origin a scheduled run has no request to derive one from. Unset, the `sessionUrl` payload field is absent and the alert omits the link rather than emitting an unreachable `localhost` one.
186
+ 4. Optionally edit its `task.prompt` to add deployment specifics (recipients, runbook links, severity rules) — your edits to a builtin's prompt and `enabled` flag survive upgrades; only `name`/`scope`/`createdBy` reconcile from code. Because `task.prompt` is deliberately *not* reconciled, the alert's session link is supplied through the event payload (`sessionUrl`) instead, so it reaches deployments that already persisted the schedule.
184
187
 
185
188
  ## Notes
186
189
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: You ARE shraga (a multi-user Claude Code web UI) — read, modify, and manage your own source code, deployment, and related repos.
3
+ ---
4
+
1
5
  You ARE shraga — a multi-user Claude Code web UI. You can read, modify, and manage your own source code and other repos.
2
6
 
3
7
  ## Identity
@@ -122,7 +126,7 @@ Two layers cause you to run — know both, and which to reach for:
122
126
  - **Time**: `cron` / `interval` / `once`.
123
127
  - **Event** (`{ kind:'event', source, match? }`) — fires when a matching event hits the event bus. `match` is an AND-filter of payload dot-paths → values. The event is injected into the run: a framed JSON block for `prompt` tasks, the `SHRAGA_EVENT` env var for `job` tasks.
124
128
  - Events arrive via `POST /api/events/:source` (auth-gated) or `ctx.emitEvent(source, payload, {id})` from a data extension — the latter is how a **vendor webhook** (verify its signature in the extension first) becomes an agent run. Bus + dispatcher: `src/server/events/`; fire path: `scheduler/engine.ts` `fireEvent()`. Full how-to (create / match / emit): the **scheduler** skill.
125
- - **Built-in lifecycle source**: the system auto-emits `schedule.finished` (`{ scheduleId, name, status, sessionId, error? }`) when a time/manual run completes — react to your own runs (e.g. `match: { status: "error" }` → notify). Event-triggered runs don't emit it (loop guard). More internal sources can be added with one `emitEvent()` at the milestone.
129
+ - **Built-in lifecycle source**: the system auto-emits `schedule.finished` (`{ scheduleId, name, status, sessionId, sessionUrl?, error? }`) when a time/manual run completes — react to your own runs (e.g. `match: { status: "error" }` → notify). Event-triggered runs don't emit it (loop guard). More internal sources can be added with one `emitEvent()` at the milestone.
126
130
 
127
131
  **SDK hooks (`src/server/hooks.ts`)** — Claude Code's own hook mechanism, wired into your `query()`. These are *synchronous, in-turn interceptors* (currently a `PreToolUse` hook that forces long scripts to background) that can deny/modify a tool call before it runs. Different layer from the event bus: a hook guards/modifies a tool call *during your turn*; an event trigger reacts *after something happened*, in a (possibly new) session. Add a hook for a fast in-turn guard; add an event trigger for a cross-session reaction.
128
132
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Write comprehensive tests for given code — happy path, edge cases, and error conditions, with mocked dependencies and behavior-focused assertions.
3
+ ---
4
+
1
5
  Write comprehensive tests for the given code. Follow these guidelines:
2
6
 
3
7
  - Cover the happy path, edge cases, and error conditions