@bendyline/gilde 0.1.7 → 0.1.9

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 (116) hide show
  1. package/README.md +19 -0
  2. package/data/chat-models/de/deepseek-v4-flash-284b-mxfp4/manifest.json +119 -0
  3. package/data/chat-models/de/deepseek-v4-flash-284b-mxfp4/versions/1.0.0/manifest.json +25 -0
  4. package/data/chat-models/de/deepseek-v4-flash-284b-q2/manifest.json +58 -12
  5. package/data/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.1.0/manifest.json +25 -0
  6. package/data/chat-models/de/deepseek-v4-flash-284b-q2q4/manifest.json +120 -0
  7. package/data/chat-models/de/deepseek-v4-flash-284b-q2q4/versions/1.0.0/manifest.json +25 -0
  8. package/data/chat-models/de/deepseek-v4-flash-284b-q4/manifest.json +53 -7
  9. package/data/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.1.0/manifest.json +223 -0
  10. package/data/chat-models/ge/gemma4-e4b-q4/manifest.json +7 -1
  11. package/data/chat-models/index.json +1 -1
  12. package/data/project-types/ca/caregiving-binder/versions/1.0.1/about.md +8 -0
  13. package/data/project-types/ca/caregiving-binder/versions/1.0.1/care.json +4 -0
  14. package/data/project-types/ca/caregiving-binder/versions/1.0.1/manifest.json +177 -0
  15. package/data/project-types/ca/caregiving-binder/versions/1.0.1/meds.json +8 -0
  16. package/data/project-types/ca/caregiving-binder/versions/1.0.1/mission.md +8 -0
  17. package/data/project-types/ca/caregiving-binder/versions/1.0.1/pages/dashboard/index.html +167 -0
  18. package/data/project-types/ch/checkers/versions/1.1.2/about.md +9 -0
  19. package/data/project-types/ch/checkers/versions/1.1.2/game.json +77 -0
  20. package/data/project-types/ch/checkers/versions/1.1.2/manifest.json +166 -0
  21. package/data/project-types/ch/checkers/versions/1.1.2/mission.md +9 -0
  22. package/data/project-types/ch/checkers/versions/1.1.2/pages/board/index.html +1091 -0
  23. package/data/project-types/ch/chess/versions/1.0.2/about.md +9 -0
  24. package/data/project-types/ch/chess/versions/1.0.2/game.json +127 -0
  25. package/data/project-types/ch/chess/versions/1.0.2/manifest.json +180 -0
  26. package/data/project-types/ch/chess/versions/1.0.2/mission.md +8 -0
  27. package/data/project-types/ch/chess/versions/1.0.2/pages/board/index.html +627 -0
  28. package/data/project-types/ch/chess/versions/1.0.3/about.md +9 -0
  29. package/data/project-types/ch/chess/versions/1.0.3/game.json +127 -0
  30. package/data/project-types/ch/chess/versions/1.0.3/manifest.json +180 -0
  31. package/data/project-types/ch/chess/versions/1.0.3/mission.md +8 -0
  32. package/data/project-types/ch/chess/versions/1.0.3/pages/board/index.html +769 -0
  33. package/data/project-types/de/design-scheme/versions/1.0.1/about.md +6 -0
  34. package/data/project-types/de/design-scheme/versions/1.0.1/manifest.json +69 -0
  35. package/data/project-types/de/design-scheme/versions/1.0.1/mission.md +3 -0
  36. package/data/project-types/de/design-scheme/versions/1.0.1/pages/gallery/index.html +105 -0
  37. package/data/project-types/de/design-scheme/versions/1.0.1/schemes/index.json +9 -0
  38. package/data/project-types/de/design-scheme/versions/1.0.1/schemes/warm-dusk.json +4 -0
  39. package/data/project-types/ev/event-planner/versions/1.0.1/about.md +7 -0
  40. package/data/project-types/ev/event-planner/versions/1.0.1/budget.json +5 -0
  41. package/data/project-types/ev/event-planner/versions/1.0.1/guests.json +10 -0
  42. package/data/project-types/ev/event-planner/versions/1.0.1/manifest.json +170 -0
  43. package/data/project-types/ev/event-planner/versions/1.0.1/mission.md +6 -0
  44. package/data/project-types/ev/event-planner/versions/1.0.1/pages/dashboard/index.html +186 -0
  45. package/data/project-types/fi/fitness-coach/versions/1.0.1/about.md +7 -0
  46. package/data/project-types/fi/fitness-coach/versions/1.0.1/manifest.json +125 -0
  47. package/data/project-types/fi/fitness-coach/versions/1.0.1/mission.md +7 -0
  48. package/data/project-types/fi/fitness-coach/versions/1.0.1/pages/dashboard/index.html +172 -0
  49. package/data/project-types/fi/fitness-coach/versions/1.0.1/training.json +6 -0
  50. package/data/project-types/fl/flashcards/versions/1.0.1/about.md +8 -0
  51. package/data/project-types/fl/flashcards/versions/1.0.1/deck.json +7 -0
  52. package/data/project-types/fl/flashcards/versions/1.0.1/manifest.json +167 -0
  53. package/data/project-types/fl/flashcards/versions/1.0.1/mission.md +6 -0
  54. package/data/project-types/fl/flashcards/versions/1.0.1/pages/review/index.html +396 -0
  55. package/data/project-types/fr/freelance-office/versions/1.0.1/about.md +6 -0
  56. package/data/project-types/fr/freelance-office/versions/1.0.1/invoices.json +9 -0
  57. package/data/project-types/fr/freelance-office/versions/1.0.1/manifest.json +142 -0
  58. package/data/project-types/fr/freelance-office/versions/1.0.1/mission.md +6 -0
  59. package/data/project-types/fr/freelance-office/versions/1.0.1/pages/dashboard/index.html +157 -0
  60. package/data/project-types/fu/fundraiser-hq/versions/1.0.1/about.md +7 -0
  61. package/data/project-types/fu/fundraiser-hq/versions/1.0.1/donations.json +7 -0
  62. package/data/project-types/fu/fundraiser-hq/versions/1.0.1/manifest.json +126 -0
  63. package/data/project-types/fu/fundraiser-hq/versions/1.0.1/mission.md +6 -0
  64. package/data/project-types/fu/fundraiser-hq/versions/1.0.1/pages/dashboard/index.html +160 -0
  65. package/data/project-types/go/go/versions/1.0.1/about.md +9 -0
  66. package/data/project-types/go/go/versions/1.0.1/game.json +103 -0
  67. package/data/project-types/go/go/versions/1.0.1/manifest.json +166 -0
  68. package/data/project-types/go/go/versions/1.0.1/mission.md +8 -0
  69. package/data/project-types/go/go/versions/1.0.1/pages/board/index.html +778 -0
  70. package/data/project-types/ho/household-budget/versions/1.0.1/about.md +6 -0
  71. package/data/project-types/ho/household-budget/versions/1.0.1/ledger.json +5 -0
  72. package/data/project-types/ho/household-budget/versions/1.0.1/manifest.json +163 -0
  73. package/data/project-types/ho/household-budget/versions/1.0.1/mission.md +6 -0
  74. package/data/project-types/ho/household-budget/versions/1.0.1/pages/dashboard/index.html +233 -0
  75. package/data/project-types/ho/household-manual/versions/1.0.1/about.md +7 -0
  76. package/data/project-types/ho/household-manual/versions/1.0.1/manifest.json +152 -0
  77. package/data/project-types/ho/household-manual/versions/1.0.1/mission.md +8 -0
  78. package/data/project-types/ho/household-manual/versions/1.0.1/pages/dashboard/index.html +157 -0
  79. package/data/project-types/ho/household-manual/versions/1.0.1/systems.json +8 -0
  80. package/data/project-types/index.json +1 -1
  81. package/data/project-types/jo/job-hunt/versions/1.0.1/about.md +10 -0
  82. package/data/project-types/jo/job-hunt/versions/1.0.1/activity.json +4 -0
  83. package/data/project-types/jo/job-hunt/versions/1.0.1/manifest.json +212 -0
  84. package/data/project-types/jo/job-hunt/versions/1.0.1/mission.md +9 -0
  85. package/data/project-types/jo/job-hunt/versions/1.0.1/pages/dashboard/index.html +327 -0
  86. package/data/project-types/jo/job-hunt/versions/1.0.1/pipeline.json +6 -0
  87. package/data/project-types/la/language-trainer/versions/1.0.1/about.md +6 -0
  88. package/data/project-types/la/language-trainer/versions/1.0.1/manifest.json +79 -0
  89. package/data/project-types/la/language-trainer/versions/1.0.1/mission.md +4 -0
  90. package/data/project-types/la/language-trainer/versions/1.0.1/pages/dashboard/index.html +153 -0
  91. package/data/project-types/la/language-trainer/versions/1.0.1/progress.json +7 -0
  92. package/data/project-types/li/life-binder/versions/1.0.1/about.md +7 -0
  93. package/data/project-types/li/life-binder/versions/1.0.1/documents.json +145 -0
  94. package/data/project-types/li/life-binder/versions/1.0.1/manifest.json +137 -0
  95. package/data/project-types/li/life-binder/versions/1.0.1/mission.md +7 -0
  96. package/data/project-types/li/life-binder/versions/1.0.1/pages/dashboard/index.html +147 -0
  97. package/data/project-types/me/meal-planner/versions/1.0.1/about.md +6 -0
  98. package/data/project-types/me/meal-planner/versions/1.0.1/manifest.json +159 -0
  99. package/data/project-types/me/meal-planner/versions/1.0.1/menu.json +5 -0
  100. package/data/project-types/me/meal-planner/versions/1.0.1/mission.md +5 -0
  101. package/data/project-types/me/meal-planner/versions/1.0.1/pages/dashboard/index.html +152 -0
  102. package/data/project-types/me/meal-planner/versions/1.0.1/pantry.json +9 -0
  103. package/data/project-types/no/novel-writing-room/versions/1.0.1/about.md +7 -0
  104. package/data/project-types/no/novel-writing-room/versions/1.0.1/chapters.json +10 -0
  105. package/data/project-types/no/novel-writing-room/versions/1.0.1/manifest.json +157 -0
  106. package/data/project-types/no/novel-writing-room/versions/1.0.1/mission.md +7 -0
  107. package/data/project-types/no/novel-writing-room/versions/1.0.1/pages/dashboard/index.html +165 -0
  108. package/data/project-types/no/novel-writing-room/versions/1.0.1/sessions.json +6 -0
  109. package/data/project-types/tr/trip-planner/versions/1.0.1/about.md +7 -0
  110. package/data/project-types/tr/trip-planner/versions/1.0.1/journal.json +4 -0
  111. package/data/project-types/tr/trip-planner/versions/1.0.1/manifest.json +193 -0
  112. package/data/project-types/tr/trip-planner/versions/1.0.1/mission.md +4 -0
  113. package/data/project-types/tr/trip-planner/versions/1.0.1/packing.json +8 -0
  114. package/data/project-types/tr/trip-planner/versions/1.0.1/pages/dashboard/index.html +215 -0
  115. package/data/project-types/tr/trip-planner/versions/1.0.1/trip.json +7 -0
  116. package/package.json +5 -2
@@ -0,0 +1,79 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "version": "1.0.1",
4
+ "releasedAt": "2026-08-01T00:00:00Z",
5
+ "extends": "content-writing",
6
+ "meesterManaged": false,
7
+ "params": {
8
+ "type": "object",
9
+ "properties": {
10
+ "language": {
11
+ "type": "string",
12
+ "title": "Which language?",
13
+ "description": "The language you want to practice, e.g. Spanish, Japanese, French.",
14
+ "default": "Spanish"
15
+ }
16
+ },
17
+ "required": [
18
+ "language"
19
+ ]
20
+ },
21
+ "nameTemplate": "{{language}} Language Trainer",
22
+ "aboutTemplate": "about.md",
23
+ "missionTemplate": "mission.md",
24
+ "gezels": [
25
+ {
26
+ "templateId": "language-trainer",
27
+ "voorman": true
28
+ }
29
+ ],
30
+ "scripts": {
31
+ "progress-store": "import { type InferredInput, defineScript, gezel } from '@bendyline/gezel-sdk';\n\nexport const meta = defineScript({\n name: 'progress-store',\n description:\n \"Read and update the student's language-learning progress (level, sessions, streak, notes). Call action:'status' at the start of a session to see where they are; action:'record' after a practice exchange to log it; action:'advance' when they're ready for the next level.\",\n inputs: {\n action: {\n type: 'string',\n description: \"One of 'status', 'record', or 'advance'.\",\n required: true,\n },\n note: {\n type: 'string',\n description: 'Optional short note to append (what was practiced, a struggle to remember).',\n },\n },\n outputs: {\n level: { type: 'number', description: 'Current level (1+).' },\n sessions: { type: 'number', description: 'Total practice sessions recorded.' },\n streak: { type: 'number', description: 'Consecutive-session streak.' },\n message: { type: 'string', description: 'Human-readable summary of the current state.' },\n },\n requires: ['workspace.read', 'workspace.write'],\n} as const);\n\nconst input = gezel.input as InferredInput<typeof meta>;\n\ninterface Progress {\n language: string;\n level: number;\n sessions: number;\n streak: number;\n notes: string[];\n}\n\nasync function load(): Promise<Progress> {\n try {\n const raw = await gezel.fs.read('progress.json');\n const p = JSON.parse(raw) as Partial<Progress>;\n return {\n language: p.language ?? 'your language',\n level: p.level ?? 1,\n sessions: p.sessions ?? 0,\n streak: p.streak ?? 0,\n notes: Array.isArray(p.notes) ? p.notes : [],\n };\n } catch {\n return { language: 'your language', level: 1, sessions: 0, streak: 0, notes: [] };\n }\n}\n\nconst p = await load();\nif (input.action === 'record') {\n p.sessions += 1;\n p.streak += 1;\n if (input.note) p.notes.push(input.note);\n} else if (input.action === 'advance') {\n p.level += 1;\n p.notes.push(`Advanced to level ${p.level}${input.note ? `: ${input.note}` : ''}`);\n}\nif (input.action !== 'status') {\n await gezel.fs.write('progress.json', `${JSON.stringify(p, null, 2)}\\n`);\n}\n\ngezel.output({\n level: p.level,\n sessions: p.sessions,\n streak: p.streak,\n message: `Learning ${p.language}: level ${p.level}, ${p.sessions} session(s), ${p.streak}-session streak.`,\n});\n"
32
+ },
33
+ "tools": [
34
+ {
35
+ "name": "record_session",
36
+ "description": "Log that the student practiced this session.",
37
+ "script": "progress-store",
38
+ "inputs": {
39
+ "type": "object",
40
+ "properties": {
41
+ "note": {
42
+ "type": "string"
43
+ }
44
+ }
45
+ },
46
+ "bind": {
47
+ "action": "record"
48
+ }
49
+ },
50
+ {
51
+ "name": "advance_level",
52
+ "description": "Advance the student to the next level.",
53
+ "script": "progress-store",
54
+ "inputs": {
55
+ "type": "object",
56
+ "properties": {
57
+ "note": {
58
+ "type": "string"
59
+ }
60
+ }
61
+ },
62
+ "bind": {
63
+ "action": "advance"
64
+ }
65
+ }
66
+ ],
67
+ "pages": {
68
+ "entry": "dashboard/index.html",
69
+ "reads": [
70
+ {
71
+ "source": "workspace",
72
+ "path": "progress.json"
73
+ }
74
+ ]
75
+ },
76
+ "workspaceSeed": [
77
+ "progress.json"
78
+ ]
79
+ }
@@ -0,0 +1,4 @@
1
+ - Practice speaking and understanding {{language}} in regular, low-pressure conversation.
2
+ - Build a daily habit — short sessions beat rare long ones.
3
+ - Advance a level only when the current one feels comfortable.
4
+ - Keep the tone encouraging: celebrate progress, treat mistakes as normal.
@@ -0,0 +1,153 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="gezel-demo" content="standalone" />
7
+ <title>Language progress</title>
8
+ <style>
9
+ :root {
10
+ color-scheme: light dark;
11
+ --bg: #faf7f2;
12
+ --card: #fff;
13
+ --ink: #2b2620;
14
+ --muted: #7a7166;
15
+ --accent: #b5651d;
16
+ --track: #ece5da;
17
+ }
18
+ @media (prefers-color-scheme: dark) {
19
+ :root {
20
+ --bg: #1c1a17;
21
+ --card: #262320;
22
+ --ink: #efe9e0;
23
+ --muted: #a59a8c;
24
+ --accent: #e0894a;
25
+ --track: #3a352f;
26
+ }
27
+ }
28
+ * { box-sizing: border-box; }
29
+ body {
30
+ margin: 0;
31
+ font: 16px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
32
+ background: var(--bg);
33
+ color: var(--ink);
34
+ padding: 2rem 1.25rem;
35
+ }
36
+ main { max-width: 640px; margin: 0 auto; }
37
+ h1 { font-size: 1.5rem; margin: 0 0 0.25rem; }
38
+ .sub { color: var(--muted); margin: 0 0 1.5rem; }
39
+ .tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; margin-bottom: 1.5rem; }
40
+ .tile {
41
+ background: var(--card);
42
+ border: 1px solid var(--track);
43
+ border-radius: 12px;
44
+ padding: 1rem;
45
+ text-align: center;
46
+ }
47
+ .tile .n { font-size: 2rem; font-weight: 700; color: var(--accent); }
48
+ .tile .l { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
49
+ .bar { background: var(--track); border-radius: 999px; height: 10px; overflow: hidden; margin: 0.5rem 0 1.5rem; }
50
+ .bar > span { display: block; height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.4s ease; }
51
+ .notes { background: var(--card); border: 1px solid var(--track); border-radius: 12px; padding: 1rem 1.25rem; }
52
+ .notes h2 { font-size: 0.95rem; margin: 0 0 0.5rem; }
53
+ .notes ul { margin: 0; padding-left: 1.1rem; color: var(--muted); }
54
+ .notes li { margin: 0.2rem 0; }
55
+ .empty { color: var(--muted); font-style: italic; }
56
+ + .demo-banner {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: space-between;
60
+ gap: 0.75rem;
61
+ margin: 0 0 0.85rem;
62
+ padding: 0.5rem 0.65rem;
63
+ border: 1px solid var(--accent, #8a5a2b);
64
+ border-radius: 6px;
65
+ background: color-mix(in srgb, var(--card, var(--surface, #fffdf8)) 88%, var(--accent, #8a5a2b));
66
+ color: var(--ink, #2b2620);
67
+ font-size: 0.8rem;
68
+ }
69
+ .demo-banner[hidden] { display: none; }
70
+ .demo-banner strong { font-weight: 700; }
71
+ .demo-reset {
72
+ flex: none;
73
+ padding: 0.25rem 0.5rem;
74
+ border: 1px solid var(--accent, #8a5a2b);
75
+ border-radius: 6px;
76
+ background: var(--card, var(--surface, #fffdf8));
77
+ color: var(--ink, #2b2620);
78
+ cursor: pointer;
79
+ font: inherit;
80
+ }
81
+ .demo-reset:hover { border-color: var(--ink, #2b2620); }
82
+ </style>
83
+ </head>
84
+ <body>
85
+ <main>
86
+ + <div class="demo-banner" data-gezel-demo-banner hidden>
87
+ <span><strong>Demo mode</strong> — sample data stays in this page.</span>
88
+ <button type="button" class="demo-reset" onclick="location.reload()">Reset demo</button>
89
+ </div>
90
+ <h1 id="title">Your language journey</h1>
91
+ <p class="sub" id="sub">Loading your progress…</p>
92
+ <div class="tiles">
93
+ <div class="tile"><div class="n" id="level">—</div><div class="l">Level</div></div>
94
+ <div class="tile"><div class="n" id="sessions">—</div><div class="l">Sessions</div></div>
95
+ <div class="tile"><div class="n" id="streak">—</div><div class="l">Day streak</div></div>
96
+ </div>
97
+ <div class="bar"><span id="levelbar" style="width: 0%"></span></div>
98
+ <div class="notes">
99
+ <h2>Recent notes</h2>
100
+ <ul id="notes"><li class="empty">No notes yet — start a conversation with your tutor.</li></ul>
101
+ </div>
102
+ </main>
103
+ <script>
104
+ // The page is served at /preview/type/<projectId>/dashboard/index.html.
105
+ // Pull the projectId out of our own path, then read the student's
106
+ // progress from the workspace preview (same origin — allowed by CSP).
107
+ (function () {
108
+ var parts = location.pathname.split('/').filter(Boolean);
109
+ var i = parts.indexOf('type');
110
+ var capability = i > 0 ? parts[i - 1] : null;
111
+ var projectId = i >= 0 ? parts[i + 1] : null;
112
+ var demoMode = !capability || !projectId;
113
+ var demoProgress = {
114
+ language: 'Dutch',
115
+ level: 7,
116
+ sessions: 18,
117
+ streak: 5,
118
+ notes: [
119
+ 'Word order is settling in after omdat clauses.',
120
+ 'Practice separable verbs in everyday errands.',
121
+ 'Listening: caught the main idea without subtitles.',
122
+ 'Next session: ordering at a café.',
123
+ ],
124
+ };
125
+ function esc(s) { return String(s).replace(/[&<>]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]; }); }
126
+ function render(p) {
127
+ document.getElementById('sub').textContent = 'Learning ' + (p.language || 'a new language');
128
+ document.getElementById('level').textContent = p.level ?? 1;
129
+ document.getElementById('sessions').textContent = p.sessions ?? 0;
130
+ document.getElementById('streak').textContent = p.streak ?? 0;
131
+ var lvl = Math.max(1, p.level ?? 1);
132
+ document.getElementById('levelbar').style.width = Math.min(100, ((lvl - 1) % 10) * 10 + 5) + '%';
133
+ var notes = Array.isArray(p.notes) ? p.notes.slice(-6).reverse() : [];
134
+ var ul = document.getElementById('notes');
135
+ if (notes.length) {
136
+ ul.innerHTML = notes.map(function (n) { return '<li>' + esc(n) + '</li>'; }).join('');
137
+ }
138
+ }
139
+ if (demoMode) {
140
+ document.querySelector('[data-gezel-demo-banner]').hidden = false;
141
+ render(demoProgress);
142
+ return;
143
+ }
144
+ fetch('/preview/' + encodeURIComponent(capability) + '/workspace/' + encodeURIComponent(projectId) + '/progress.json', { cache: 'no-store' })
145
+ .then(function (r) { if (!r.ok) throw new Error('no progress yet'); return r.json(); })
146
+ .then(render)
147
+ .catch(function () {
148
+ document.getElementById('sub').textContent = 'No sessions recorded yet — say hello to your tutor to begin.';
149
+ });
150
+ })();
151
+ </script>
152
+ </body>
153
+ </html>
@@ -0,0 +1,7 @@
1
+ {
2
+ "language": "{{language}}",
3
+ "level": 1,
4
+ "sessions": 0,
5
+ "streak": 0,
6
+ "notes": []
7
+ }
@@ -0,0 +1,7 @@
1
+ The binder {{household}} hopes never to need — complete, current, and findable.
2
+ Your Archivaris keeps the checklist: which documents exist, where the originals
3
+ live, which are missing, which are due a review. Contents are never stored;
4
+ locations are. Nothing leaves this machine — that privacy is the point.
5
+
6
+ The **Output** tab shows the completeness picture at a glance. Start anywhere:
7
+ tell your Archivaris about one document you know exists.
@@ -0,0 +1,145 @@
1
+ {
2
+ "version": 1,
3
+ "stages": [
4
+ "missing",
5
+ "present"
6
+ ],
7
+ "records": [
8
+ {
9
+ "id": "doc-1",
10
+ "status": "missing",
11
+ "fields": {
12
+ "name": "Will",
13
+ "note": "The signed original, and who holds copies."
14
+ },
15
+ "createdAt": "2026-07-18T00:00:00.000Z",
16
+ "updatedAt": "2026-07-18T00:00:00.000Z",
17
+ "history": [
18
+ {
19
+ "at": "2026-07-18T00:00:00.000Z",
20
+ "from": null,
21
+ "to": "missing"
22
+ }
23
+ ]
24
+ },
25
+ {
26
+ "id": "doc-2",
27
+ "status": "missing",
28
+ "fields": {
29
+ "name": "Medical directives",
30
+ "note": "Living will / healthcare proxy."
31
+ },
32
+ "createdAt": "2026-07-18T00:00:00.000Z",
33
+ "updatedAt": "2026-07-18T00:00:00.000Z",
34
+ "history": [
35
+ {
36
+ "at": "2026-07-18T00:00:00.000Z",
37
+ "from": null,
38
+ "to": "missing"
39
+ }
40
+ ]
41
+ },
42
+ {
43
+ "id": "doc-3",
44
+ "status": "missing",
45
+ "fields": {
46
+ "name": "Life insurance policy",
47
+ "note": "Provider, policy number, where the paperwork lives."
48
+ },
49
+ "createdAt": "2026-07-18T00:00:00.000Z",
50
+ "updatedAt": "2026-07-18T00:00:00.000Z",
51
+ "history": [
52
+ {
53
+ "at": "2026-07-18T00:00:00.000Z",
54
+ "from": null,
55
+ "to": "missing"
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "id": "doc-4",
61
+ "status": "missing",
62
+ "fields": {
63
+ "name": "Home or renters insurance",
64
+ "note": "Provider and policy number."
65
+ },
66
+ "createdAt": "2026-07-18T00:00:00.000Z",
67
+ "updatedAt": "2026-07-18T00:00:00.000Z",
68
+ "history": [
69
+ {
70
+ "at": "2026-07-18T00:00:00.000Z",
71
+ "from": null,
72
+ "to": "missing"
73
+ }
74
+ ]
75
+ },
76
+ {
77
+ "id": "doc-5",
78
+ "status": "missing",
79
+ "fields": {
80
+ "name": "Accounts list",
81
+ "note": "Banks, retirement, investments — institutions only, no credentials."
82
+ },
83
+ "createdAt": "2026-07-18T00:00:00.000Z",
84
+ "updatedAt": "2026-07-18T00:00:00.000Z",
85
+ "history": [
86
+ {
87
+ "at": "2026-07-18T00:00:00.000Z",
88
+ "from": null,
89
+ "to": "missing"
90
+ }
91
+ ]
92
+ },
93
+ {
94
+ "id": "doc-6",
95
+ "status": "missing",
96
+ "fields": {
97
+ "name": "Passwords location",
98
+ "note": "Where the password manager or list lives, not the passwords."
99
+ },
100
+ "createdAt": "2026-07-18T00:00:00.000Z",
101
+ "updatedAt": "2026-07-18T00:00:00.000Z",
102
+ "history": [
103
+ {
104
+ "at": "2026-07-18T00:00:00.000Z",
105
+ "from": null,
106
+ "to": "missing"
107
+ }
108
+ ]
109
+ },
110
+ {
111
+ "id": "doc-7",
112
+ "status": "missing",
113
+ "fields": {
114
+ "name": "Emergency contacts",
115
+ "note": "Who to call first: family, lawyer, doctor."
116
+ },
117
+ "createdAt": "2026-07-18T00:00:00.000Z",
118
+ "updatedAt": "2026-07-18T00:00:00.000Z",
119
+ "history": [
120
+ {
121
+ "at": "2026-07-18T00:00:00.000Z",
122
+ "from": null,
123
+ "to": "missing"
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "id": "doc-8",
129
+ "status": "missing",
130
+ "fields": {
131
+ "name": "Deeds and titles",
132
+ "note": "House, vehicles — where the originals live."
133
+ },
134
+ "createdAt": "2026-07-18T00:00:00.000Z",
135
+ "updatedAt": "2026-07-18T00:00:00.000Z",
136
+ "history": [
137
+ {
138
+ "at": "2026-07-18T00:00:00.000Z",
139
+ "from": null,
140
+ "to": "missing"
141
+ }
142
+ ]
143
+ }
144
+ ]
145
+ }
@@ -0,0 +1,137 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "version": "1.0.1",
4
+ "releasedAt": "2026-08-01T00:00:00Z",
5
+ "meesterManaged": false,
6
+ "params": {
7
+ "type": "object",
8
+ "properties": {
9
+ "household": {
10
+ "type": "string",
11
+ "title": "Who is this binder for?",
12
+ "description": "e.g. 'our family', 'Mom', 'me'.",
13
+ "default": "our family"
14
+ }
15
+ },
16
+ "required": [
17
+ "household"
18
+ ]
19
+ },
20
+ "nameTemplate": "Life Binder",
21
+ "aboutTemplate": "about.md",
22
+ "missionTemplate": "mission.md",
23
+ "gezels": [
24
+ {
25
+ "templateId": "archivaris",
26
+ "voorman": true
27
+ }
28
+ ],
29
+ "tools": [
30
+ {
31
+ "name": "record_document",
32
+ "description": "Record that a document exists and where the original lives.",
33
+ "script": "binder-store",
34
+ "inputs": {
35
+ "type": "object",
36
+ "properties": {
37
+ "name": {
38
+ "type": "string"
39
+ },
40
+ "location": {
41
+ "type": "string"
42
+ },
43
+ "note": {
44
+ "type": "string"
45
+ }
46
+ },
47
+ "required": [
48
+ "name"
49
+ ]
50
+ },
51
+ "bind": {
52
+ "action": "record_document"
53
+ }
54
+ },
55
+ {
56
+ "name": "mark_missing",
57
+ "description": "Mark a checklist item as a known gap.",
58
+ "script": "binder-store",
59
+ "inputs": {
60
+ "type": "object",
61
+ "properties": {
62
+ "id": {
63
+ "type": "string"
64
+ },
65
+ "name": {
66
+ "type": "string"
67
+ }
68
+ }
69
+ },
70
+ "bind": {
71
+ "action": "mark_missing"
72
+ }
73
+ },
74
+ {
75
+ "name": "mark_reviewed",
76
+ "description": "Confirm a document was just reviewed and is current.",
77
+ "script": "binder-store",
78
+ "inputs": {
79
+ "type": "object",
80
+ "properties": {
81
+ "id": {
82
+ "type": "string"
83
+ },
84
+ "name": {
85
+ "type": "string"
86
+ }
87
+ }
88
+ },
89
+ "bind": {
90
+ "action": "mark_reviewed"
91
+ }
92
+ },
93
+ {
94
+ "name": "binder_status",
95
+ "description": "The completeness picture: what's in place, missing, or due a review.",
96
+ "script": "binder-store",
97
+ "inputs": {
98
+ "type": "object",
99
+ "properties": {}
100
+ },
101
+ "bind": {
102
+ "action": "status"
103
+ }
104
+ },
105
+ {
106
+ "name": "checklist",
107
+ "description": "Read the whole checklist with locations.",
108
+ "script": "binder-store",
109
+ "inputs": {
110
+ "type": "object",
111
+ "properties": {}
112
+ },
113
+ "bind": {
114
+ "action": "checklist"
115
+ }
116
+ }
117
+ ],
118
+ "craftbooks": [
119
+ "annual-document-review"
120
+ ],
121
+ "schedules": [],
122
+ "pages": {
123
+ "entry": "dashboard/index.html",
124
+ "reads": [
125
+ {
126
+ "source": "workspace",
127
+ "path": "documents.json"
128
+ }
129
+ ]
130
+ },
131
+ "workspaceSeed": [
132
+ "documents.json"
133
+ ],
134
+ "scripts": {
135
+ "binder-store": "import { type InferredInput, defineScript, gezel } from '@bendyline/gezel-sdk';\nimport { rosterStore } from '@bendyline/gezel-sdk/stores';\n\nexport const meta = defineScript({\n name: 'binder-store',\n description:\n \"Read and update the life binder (documents.json). Call action:'status' for the completeness picture; 'record_document' when a document exists (name + where the original lives); 'mark_missing' / 'mark_reviewed' as reality changes; 'checklist' to read everything.\",\n inputs: {\n action: {\n type: 'string',\n description:\n \"One of 'status', 'record_document', 'mark_missing', 'mark_reviewed', or 'checklist'.\",\n required: true,\n },\n name: { type: 'string', description: \"Document name, e.g. 'Will', 'Home insurance policy'.\" },\n location: { type: 'string', description: 'Where the original lives (drawer, safe, provider).' },\n note: { type: 'string', description: 'Anything a trusted person should know about it.' },\n id: { type: 'string', description: \"Document id, e.g. 'doc-2'.\" },\n },\n outputs: {\n total: { type: 'number', description: 'Documents on the checklist.' },\n present: { type: 'number', description: 'Recorded as existing.' },\n missing: { type: 'number', description: 'Known gaps.' },\n stale: { type: 'number', description: 'Present but unreviewed for over a year.' },\n summary: { type: 'string', description: 'The completeness picture.' },\n },\n requires: ['workspace.read', 'workspace.write'],\n} as const);\n\nconst input = gezel.input as InferredInput<typeof meta>;\n\n// ── binder-rules-start ──\n// Pure derivations over rosterStore-shaped document records: statuses are\n// missing -> present; staleness is derived (present + unreviewed > 365d).\n\nvar YEAR_MS = 365 * 24 * 60 * 60 * 1000;\n\nfunction isStale(record, nowMs) {\n if (record.status !== 'present') return false;\n var reviewed = record.fields && typeof record.fields.reviewedAt === 'string'\n ? Date.parse(record.fields.reviewedAt)\n : Date.parse(record.updatedAt);\n return isFinite(reviewed) && nowMs - reviewed > YEAR_MS;\n}\n\nfunction binderShape(records, nowMs) {\n var present = 0;\n var missing = [];\n var stale = [];\n records.forEach(function (r) {\n if (r.status === 'present') {\n present += 1;\n if (isStale(r, nowMs)) stale.push(r);\n } else {\n missing.push(r);\n }\n });\n return { present: present, missing: missing, stale: stale };\n}\n\nfunction binderLine(records, nowMs) {\n var shape = binderShape(records, nowMs);\n var gaps = shape.missing\n .map(function (r) {\n return r.fields && r.fields.name ? r.fields.name : r.id;\n })\n .join(', ');\n var staleNames = shape.stale\n .map(function (r) {\n return r.fields && r.fields.name ? r.fields.name : r.id;\n })\n .join(', ');\n return (\n shape.present +\n ' of ' +\n records.length +\n ' in place' +\n (gaps ? '. Missing: ' + gaps : '. Nothing missing') +\n (staleNames ? '. Due a review: ' + staleNames + '.' : '.')\n );\n}\n// ── binder-rules-end ──\n\nconst binder = rosterStore(gezel.fs, 'documents.json', {\n stages: ['missing', 'present'],\n idPrefix: 'doc',\n});\n\nasync function resolveDoc(): Promise<string> {\n if (input.id) return input.id;\n if (input.name) {\n const wanted = input.name.toLowerCase();\n const matches = (await binder.list()).filter(\n (r) => String(r.fields.name ?? '').toLowerCase() === wanted,\n );\n if (matches.length === 1) return matches[0]!.id;\n }\n throw new Error(\"Pass 'id' (e.g. 'doc-2') or an exact document 'name'.\");\n}\n\nif (input.action === 'record_document') {\n if (!input.name) throw new Error(\"record_document needs 'name'.\");\n const existing = (await binder.list()).find(\n (r) => String(r.fields.name ?? '').toLowerCase() === input.name!.toLowerCase(),\n );\n if (existing) {\n await binder.update(existing.id, {\n fields: {\n ...(input.location ? { location: input.location } : {}),\n ...(input.note ? { note: input.note } : {}),\n reviewedAt: new Date().toISOString(),\n },\n });\n await binder.transition(existing.id, 'present');\n } else {\n await binder.add({\n status: 'present',\n fields: {\n name: input.name,\n ...(input.location ? { location: input.location } : {}),\n ...(input.note ? { note: input.note } : {}),\n reviewedAt: new Date().toISOString(),\n },\n });\n }\n} else if (input.action === 'mark_missing') {\n await binder.transition(await resolveDoc(), 'missing');\n} else if (input.action === 'mark_reviewed') {\n const id = await resolveDoc();\n await binder.update(id, { fields: { reviewedAt: new Date().toISOString() } });\n await binder.transition(id, 'present');\n} else if (input.action !== 'status' && input.action !== 'checklist') {\n throw new Error(\n `Unknown action '${input.action}'. Use status, record_document, mark_missing, mark_reviewed, or checklist.`,\n );\n}\n\nconst records = await binder.list();\nconst shape = binderShape(records, Date.now());\nconst listing =\n input.action === 'checklist'\n ? records\n .map(\n (r) =>\n `${r.id} [${r.status}${isStale(r, Date.now()) ? ', stale' : ''}] ${String(r.fields.name ?? '?')}${r.fields.location ? ` — ${String(r.fields.location)}` : ''}`,\n )\n .join('\\n') || 'The checklist is empty.'\n : '';\n\ngezel.output({\n total: records.length,\n present: shape.present,\n missing: shape.missing.length,\n stale: shape.stale.length,\n summary: listing || binderLine(records, Date.now()),\n});\n"
136
+ }
137
+ }
@@ -0,0 +1,7 @@
1
+ - Every checklist item is either recorded (with where the original lives) or a
2
+ known, owned gap — nothing ambiguous.
3
+ - The one-page test holds: a trusted person could find what they need in five
4
+ minutes from what's recorded here.
5
+ - Anything unreviewed for a year gets flagged and re-confirmed.
6
+ - Document contents are never stored; locations and instructions are. Nothing
7
+ leaves this machine.