@ghostpaw/questlog 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -18
- package/SKILL.md +29 -15
- package/dist/chunk-3B6FMHZU.js +384 -0
- package/dist/chunk-3Y5F3SMB.js +4308 -0
- package/dist/chunk-RUSE7ZFF.js +58 -0
- package/dist/chunk-SVWAEAKC.js +5 -0
- package/dist/cli.js +11 -7468
- package/dist/cli_main-ED5BJPSR.js +626 -0
- package/dist/index.cjs +64 -45
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +64 -45
- package/dist/mcp-server.js +71 -46
- package/dist/mcp.cjs +65 -46
- package/dist/mcp.js +65 -46
- package/dist/open_questlog_db-SH3DAU4C.js +2 -0
- package/dist/questlog_skill_spec-JLZH3JL2.js +807 -0
- package/dist/serve_questlog_mcp-J4ZHNEOT.js +212 -0
- package/dist/skill_markdown-7HCMSJYR.js +80 -0
- package/package.json +7 -3
- package/skills/questlog/SKILL.md +29 -15
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { openQuestlogDb } from './chunk-3B6FMHZU.js';
|
|
3
|
+
import { questlogMcpInstructions } from './chunk-SVWAEAKC.js';
|
|
4
|
+
import { validateInput, isErrorResult, questlogVersion, resolveQuestlogDbPath } from './chunk-RUSE7ZFF.js';
|
|
5
|
+
import { questlogSurfaceTools } from './chunk-3Y5F3SMB.js';
|
|
6
|
+
|
|
7
|
+
// src/surfaces/mcp_server.ts
|
|
8
|
+
var MCP_LATEST_PROTOCOL_VERSION = "2026-07-28";
|
|
9
|
+
var MCP_SUPPORTED_PROTOCOL_VERSIONS = [
|
|
10
|
+
MCP_LATEST_PROTOCOL_VERSION,
|
|
11
|
+
"2025-11-25",
|
|
12
|
+
"2025-06-18",
|
|
13
|
+
"2025-03-26",
|
|
14
|
+
"2024-11-05"
|
|
15
|
+
];
|
|
16
|
+
function createMcpServer(options) {
|
|
17
|
+
let initialized = false;
|
|
18
|
+
let context;
|
|
19
|
+
const serverInfo = { name: options.name, version: options.version };
|
|
20
|
+
const record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21
|
+
const error = (id, code, message, data) => ({
|
|
22
|
+
jsonrpc: "2.0",
|
|
23
|
+
id,
|
|
24
|
+
error: { code, message, ...data === void 0 ? {} : { data } }
|
|
25
|
+
});
|
|
26
|
+
const handleMessage = async (msg) => {
|
|
27
|
+
if (!record(msg) || msg.jsonrpc !== "2.0" || typeof msg.method !== "string" || Object.hasOwn(msg, "id") && msg.id !== null && typeof msg.id !== "string" && typeof msg.id !== "number")
|
|
28
|
+
return error(null, -32600, "Invalid Request");
|
|
29
|
+
if (!Object.hasOwn(msg, "id")) return void 0;
|
|
30
|
+
const id = msg.id;
|
|
31
|
+
if (msg.params !== void 0 && !record(msg.params)) return error(id, -32602, "Invalid params");
|
|
32
|
+
const params = record(msg.params) ? msg.params : {};
|
|
33
|
+
const meta = record(params._meta) ? params._meta : {};
|
|
34
|
+
const requested = meta["io.modelcontextprotocol/protocolVersion"];
|
|
35
|
+
const modern = requested !== void 0;
|
|
36
|
+
if (modern && !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(
|
|
37
|
+
requested
|
|
38
|
+
))
|
|
39
|
+
return error(id, -32022, "Unsupported protocol version", {
|
|
40
|
+
supported: [...MCP_SUPPORTED_PROTOCOL_VERSIONS],
|
|
41
|
+
requested
|
|
42
|
+
});
|
|
43
|
+
const result = (value) => ({
|
|
44
|
+
jsonrpc: "2.0",
|
|
45
|
+
id,
|
|
46
|
+
result: modern ? {
|
|
47
|
+
...value,
|
|
48
|
+
resultType: "complete",
|
|
49
|
+
_meta: { "io.modelcontextprotocol/serverInfo": serverInfo }
|
|
50
|
+
} : value
|
|
51
|
+
});
|
|
52
|
+
if (!modern && msg.method === "initialize") {
|
|
53
|
+
initialized = true;
|
|
54
|
+
const version = MCP_SUPPORTED_PROTOCOL_VERSIONS.slice(1).find((v) => v === params.protocolVersion) ?? "2025-11-25";
|
|
55
|
+
return result({
|
|
56
|
+
protocolVersion: version,
|
|
57
|
+
capabilities: { tools: { listChanged: false } },
|
|
58
|
+
serverInfo: { ...serverInfo, ...options.title ? { title: options.title } : {} },
|
|
59
|
+
...options.instructions ? { instructions: options.instructions } : {}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (!modern && !initialized)
|
|
63
|
+
return error(
|
|
64
|
+
id,
|
|
65
|
+
-32602,
|
|
66
|
+
`Protocol version required. Supported versions: ${MCP_SUPPORTED_PROTOCOL_VERSIONS.join(", ")}`
|
|
67
|
+
);
|
|
68
|
+
if (modern && !record(meta["io.modelcontextprotocol/clientCapabilities"]))
|
|
69
|
+
return error(id, -32602, "clientCapabilities must be an object");
|
|
70
|
+
switch (msg.method) {
|
|
71
|
+
case "ping":
|
|
72
|
+
return result({});
|
|
73
|
+
case "server/discover":
|
|
74
|
+
return result({
|
|
75
|
+
supportedVersions: [...MCP_SUPPORTED_PROTOCOL_VERSIONS],
|
|
76
|
+
capabilities: { tools: {} },
|
|
77
|
+
...options.instructions ? { instructions: options.instructions } : {},
|
|
78
|
+
ttlMs: 6e4,
|
|
79
|
+
cacheScope: "public"
|
|
80
|
+
});
|
|
81
|
+
case "tools/list":
|
|
82
|
+
return result({
|
|
83
|
+
tools: options.tools.map((tool) => ({
|
|
84
|
+
name: tool.name,
|
|
85
|
+
...tool.title ? { title: tool.title } : {},
|
|
86
|
+
description: tool.description + (tool.whenToUse ? `
|
|
87
|
+
|
|
88
|
+
Use when: ${tool.whenToUse}` : "") + (tool.whenNotToUse ? `
|
|
89
|
+
Not for: ${tool.whenNotToUse}` : ""),
|
|
90
|
+
inputSchema: tool.inputSchema,
|
|
91
|
+
annotations: options.annotations?.(tool) ?? {
|
|
92
|
+
readOnlyHint: tool.readOnly ?? false,
|
|
93
|
+
destructiveHint: !tool.readOnly,
|
|
94
|
+
idempotentHint: tool.readOnly ?? false,
|
|
95
|
+
openWorldHint: false
|
|
96
|
+
}
|
|
97
|
+
})),
|
|
98
|
+
...modern ? { ttlMs: 6e4, cacheScope: "public" } : {}
|
|
99
|
+
});
|
|
100
|
+
case "tools/call": {
|
|
101
|
+
const tool = options.tools.find((tool2) => tool2.name === params.name);
|
|
102
|
+
if (!tool) return error(id, -32602, `Unknown tool: ${String(params.name)}`);
|
|
103
|
+
const input = params.arguments === void 0 ? {} : params.arguments;
|
|
104
|
+
const errors = validateInput(tool.inputSchema, input);
|
|
105
|
+
if (errors.length)
|
|
106
|
+
return result({ content: [{ type: "text", text: errors.join("\n") }], isError: true });
|
|
107
|
+
try {
|
|
108
|
+
context ??= Promise.resolve().then(options.context);
|
|
109
|
+
const value = await tool.handler(await context, input);
|
|
110
|
+
return result({
|
|
111
|
+
content: [{ type: "text", text: JSON.stringify(value) ?? "null" }],
|
|
112
|
+
...record(value) ? { structuredContent: value } : {},
|
|
113
|
+
isError: (options.isErrorResult ?? isErrorResult)(value)
|
|
114
|
+
});
|
|
115
|
+
} catch (cause) {
|
|
116
|
+
return result({
|
|
117
|
+
content: [
|
|
118
|
+
{ type: "text", text: cause instanceof Error ? cause.message : String(cause) }
|
|
119
|
+
],
|
|
120
|
+
isError: true
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
default:
|
|
125
|
+
return error(id, -32601, "Method not found");
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
handleMessage,
|
|
130
|
+
async handleLine(line) {
|
|
131
|
+
let msg;
|
|
132
|
+
try {
|
|
133
|
+
msg = JSON.parse(line);
|
|
134
|
+
} catch {
|
|
135
|
+
return JSON.stringify(error(null, -32700, "Parse error"));
|
|
136
|
+
}
|
|
137
|
+
const response = await handleMessage(msg);
|
|
138
|
+
return response === void 0 ? void 0 : JSON.stringify(response);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/surfaces/mcp_stdio.ts
|
|
144
|
+
async function serveMcpStdio(server, options = {}) {
|
|
145
|
+
const input = options.input ?? process.stdin;
|
|
146
|
+
const output = options.output ?? process.stdout;
|
|
147
|
+
input.setEncoding("utf8");
|
|
148
|
+
let buffer = "";
|
|
149
|
+
const respond = async (line) => {
|
|
150
|
+
if (!line.trim()) return;
|
|
151
|
+
const response = await server.handleLine(line.replace(/\r$/, ""));
|
|
152
|
+
if (response !== void 0)
|
|
153
|
+
await new Promise(
|
|
154
|
+
(resolve, reject) => output.write(`${response}
|
|
155
|
+
`, (error) => error ? reject(error) : resolve())
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
for await (const chunk of input) {
|
|
159
|
+
buffer += String(chunk);
|
|
160
|
+
let end = buffer.indexOf("\n");
|
|
161
|
+
while (end !== -1) {
|
|
162
|
+
const line = buffer.slice(0, end);
|
|
163
|
+
buffer = buffer.slice(end + 1);
|
|
164
|
+
await respond(line);
|
|
165
|
+
end = buffer.indexOf("\n");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
await respond(buffer);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/surface/questlog_mcp_options.ts
|
|
172
|
+
function questlogMcpOptions(context) {
|
|
173
|
+
return {
|
|
174
|
+
name: "ghostpaw-questlog",
|
|
175
|
+
version: questlogVersion,
|
|
176
|
+
title: "Questlog",
|
|
177
|
+
instructions: questlogMcpInstructions,
|
|
178
|
+
tools: questlogSurfaceTools,
|
|
179
|
+
context,
|
|
180
|
+
annotations: (tool) => ({
|
|
181
|
+
readOnlyHint: tool.readOnly ?? false,
|
|
182
|
+
destructiveHint: Boolean(
|
|
183
|
+
tool.inputSchema.properties?.action?.enum?.some(
|
|
184
|
+
(action) => typeof action === "string" && /delete|retire|merge|trash|hide|remove|replace|archive|abandon|dismiss/.test(action)
|
|
185
|
+
)
|
|
186
|
+
),
|
|
187
|
+
idempotentHint: tool.readOnly ?? false,
|
|
188
|
+
openWorldHint: false
|
|
189
|
+
})
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/surface/serve_questlog_mcp.ts
|
|
194
|
+
async function serveQuestlogMcp(options = {}) {
|
|
195
|
+
let owned;
|
|
196
|
+
const server = createMcpServer(
|
|
197
|
+
questlogMcpOptions(async () => {
|
|
198
|
+
if (options.db) return options.db;
|
|
199
|
+
owned = await openQuestlogDb(
|
|
200
|
+
resolveQuestlogDbPath(options.dbPath === void 0 ? {} : { flag: options.dbPath })
|
|
201
|
+
);
|
|
202
|
+
return owned;
|
|
203
|
+
})
|
|
204
|
+
);
|
|
205
|
+
try {
|
|
206
|
+
await serveMcpStdio(server);
|
|
207
|
+
} finally {
|
|
208
|
+
owned?.close();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export { serveQuestlogMcp };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// src/surfaces/skill_markdown.ts
|
|
3
|
+
function renderSkillMarkdown(spec, { referencesBase = "references" } = {}) {
|
|
4
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(spec.name) || spec.name.length > 64)
|
|
5
|
+
throw new Error("Invalid skill name");
|
|
6
|
+
if (!spec.description.trim() || spec.description.length > 1024 || !spec.description.includes("Use when"))
|
|
7
|
+
throw new Error("Invalid skill description");
|
|
8
|
+
if (spec.compatibility && spec.compatibility.length > 500)
|
|
9
|
+
throw new Error("Invalid compatibility");
|
|
10
|
+
const lines = ["---", `name: ${spec.name}`, `description: ${JSON.stringify(spec.description)}`];
|
|
11
|
+
for (const key of ["license", "compatibility"])
|
|
12
|
+
if (spec[key]) lines.push(`${key}: ${JSON.stringify(spec[key])}`);
|
|
13
|
+
if (spec.metadata) {
|
|
14
|
+
lines.push("metadata:");
|
|
15
|
+
for (const key of Object.keys(spec.metadata).sort())
|
|
16
|
+
lines.push(` ${JSON.stringify(key)}: ${JSON.stringify(spec.metadata[key])}`);
|
|
17
|
+
}
|
|
18
|
+
lines.push(
|
|
19
|
+
"---",
|
|
20
|
+
"",
|
|
21
|
+
`# ${spec.name}`,
|
|
22
|
+
"",
|
|
23
|
+
spec.about,
|
|
24
|
+
"",
|
|
25
|
+
"## Calling tools",
|
|
26
|
+
"",
|
|
27
|
+
`MCP: connect to ${spec.server}, then call a tool by name with its JSON arguments.`,
|
|
28
|
+
"",
|
|
29
|
+
`CLI: \`${spec.bin} call <tool> '<JSON object>'\` or \`${spec.bin} <tool> --parameter value\`${spec.packageName ? ` (without a global install: \`npx -y ${spec.packageName} <tool> ...\`)` : ""}.`,
|
|
30
|
+
"",
|
|
31
|
+
`Inspect schemas with \`${spec.bin} describe <tool>\`. Use \`--db <path>\` to select a database.`,
|
|
32
|
+
""
|
|
33
|
+
);
|
|
34
|
+
for (const tool of spec.tools) {
|
|
35
|
+
lines.push(
|
|
36
|
+
`## ${tool.name}`,
|
|
37
|
+
"",
|
|
38
|
+
tool.description,
|
|
39
|
+
"",
|
|
40
|
+
`Use when: ${tool.whenToUse ?? ""}`,
|
|
41
|
+
"",
|
|
42
|
+
`Not for: ${tool.whenNotToUse ?? ""}`,
|
|
43
|
+
"",
|
|
44
|
+
tool.readOnly ? "Read-only." : `Writes: ${tool.sideEffects ?? "state"}.`,
|
|
45
|
+
"",
|
|
46
|
+
"| Parameter | Type | Required | Values / description |",
|
|
47
|
+
"| --- | --- | --- | --- |"
|
|
48
|
+
);
|
|
49
|
+
for (const [name, property] of Object.entries(tool.inputSchema.properties ?? {}))
|
|
50
|
+
lines.push(
|
|
51
|
+
`| ${name} | ${property.type ?? property.oneOf?.map((branch) => branch.type).join(" / ") ?? "any"} | ${tool.inputSchema.required?.includes(name) ? "yes" : "no"} | ${(property.enum ? `${property.enum.join(", ")}. ` : "") + (property.description ?? "").replaceAll("|", "\\|").replaceAll("\n", " ")} |`
|
|
52
|
+
);
|
|
53
|
+
lines.push("");
|
|
54
|
+
}
|
|
55
|
+
lines.push(
|
|
56
|
+
"## Workflow guides",
|
|
57
|
+
"",
|
|
58
|
+
...spec.workflows.map(
|
|
59
|
+
(workflow) => `- [${workflow.name}](${referencesBase}/${workflow.name}.md): ${workflow.description}`
|
|
60
|
+
),
|
|
61
|
+
"",
|
|
62
|
+
"## Principles",
|
|
63
|
+
"",
|
|
64
|
+
...spec.principles.map((principle) => `- ${principle}`),
|
|
65
|
+
""
|
|
66
|
+
);
|
|
67
|
+
const output = lines.join("\n");
|
|
68
|
+
if (!spec.cheatSheet) return output;
|
|
69
|
+
const title = `# ${spec.name}
|
|
70
|
+
|
|
71
|
+
`;
|
|
72
|
+
const start = output.indexOf(title) + title.length;
|
|
73
|
+
return `${output.slice(0, start)}${spec.cheatSheet}
|
|
74
|
+
|
|
75
|
+
## Appendix: MCP and tool calls
|
|
76
|
+
|
|
77
|
+
${output.slice(start).replace(/^## /gm, "### ")}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { renderSkillMarkdown };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostpaw/questlog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Unified task and calendar model for Node.js — SQLite, zero dependencies, with a built-in LLM tool facade",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -65,7 +65,10 @@
|
|
|
65
65
|
"check:api": "node scripts/guard/api.mjs",
|
|
66
66
|
"check:consumer": "node scripts/guard/consumer.mjs",
|
|
67
67
|
"check:startup": "node scripts/guard/startup.mjs",
|
|
68
|
-
"mcpb": "node scripts/mcpb/build.mjs"
|
|
68
|
+
"mcpb": "node scripts/mcpb/build.mjs",
|
|
69
|
+
"sea": "node scripts/sea/build.mjs",
|
|
70
|
+
"sea:smoke": "node scripts/sea/smoke.mjs",
|
|
71
|
+
"sea:bench": "node scripts/sea/bench.mjs"
|
|
69
72
|
},
|
|
70
73
|
"engines": {
|
|
71
74
|
"node": ">=24"
|
|
@@ -132,7 +135,8 @@
|
|
|
132
135
|
"typescript": "^5.9.3"
|
|
133
136
|
},
|
|
134
137
|
"bin": {
|
|
135
|
-
"ghostpaw-questlog": "./dist/cli.js"
|
|
138
|
+
"ghostpaw-questlog": "./dist/cli.js",
|
|
139
|
+
"questlog": "./dist/cli.js"
|
|
136
140
|
},
|
|
137
141
|
"mcpName": "io.github.GhostPawJS/questlog"
|
|
138
142
|
}
|
package/skills/questlog/SKILL.md
CHANGED
|
@@ -7,9 +7,23 @@ compatibility: "Node.js 24 or newer. MCP stdio or ghostpaw-questlog CLI."
|
|
|
7
7
|
|
|
8
8
|
# questlog
|
|
9
9
|
|
|
10
|
+
`questlog` and `ghostpaw-questlog` are the same binary.
|
|
11
|
+
|
|
12
|
+
- `questlog add --title "..." --tag a,b --due tomorrow`
|
|
13
|
+
- `questlog list [--view <view>]`: questlines, quests.active, quests.available, quests.blocked, quests.deferred, quests.due_soon, quests.in_progress, quests.missed_scheduled, quests.open, quests.overdue, quests.resolved, quests.scheduled_for_day, quests.scheduled_now, repeatables.due_anchors, rumors.
|
|
14
|
+
- `questlog done <id> --outcome "..."`
|
|
15
|
+
- `questlog search <words>`
|
|
16
|
+
- `questlog show <id>`
|
|
17
|
+
- Use `--json` on any plain command.
|
|
18
|
+
- Exit codes: 0 ok / 1 error / 2 usage / 3 needs input.
|
|
19
|
+
- Database: `~/.ghostpaw/questlog.db`; override with `--db` or `GHOSTPAW_QUESTLOG_DB`.
|
|
20
|
+
- Use one database per agent or project.
|
|
21
|
+
|
|
22
|
+
## Appendix: MCP and tool calls
|
|
23
|
+
|
|
10
24
|
Questlog manages local tasks, calendar commitments, and recurring work. Search before creating work, inspect before changing it, and keep uncertain work as rumors. Use unlock prerequisites to sequence work. run_quest refuses blocked starts unless force is true. Review commitments and resolve work with an honest outcome.
|
|
11
25
|
|
|
12
|
-
|
|
26
|
+
### Calling tools
|
|
13
27
|
|
|
14
28
|
MCP: connect to ghostpaw-questlog, then call a tool by name with its JSON arguments.
|
|
15
29
|
|
|
@@ -17,7 +31,7 @@ CLI: `ghostpaw-questlog call <tool> '<JSON object>'` or `ghostpaw-questlog <tool
|
|
|
17
31
|
|
|
18
32
|
Inspect schemas with `ghostpaw-questlog describe <tool>`. Use `--db <path>` to select a database.
|
|
19
33
|
|
|
20
|
-
|
|
34
|
+
### search_questlog
|
|
21
35
|
|
|
22
36
|
Search quests and rumors by text when you need to find an existing item before inspecting or changing it.
|
|
23
37
|
|
|
@@ -34,7 +48,7 @@ Read-only.
|
|
|
34
48
|
| kinds | array | no | Optional entity kinds to search. |
|
|
35
49
|
| mode | string | no | browse, identify_one. Whether to browse results normally or ask for clarification when several matches are found. |
|
|
36
50
|
|
|
37
|
-
|
|
51
|
+
### review_questlog
|
|
38
52
|
|
|
39
53
|
Review one operational questlog surface such as available quests, open rumors, blocked work, or due repeatable anchors.
|
|
40
54
|
|
|
@@ -50,7 +64,7 @@ Read-only.
|
|
|
50
64
|
| filters | object | no | Optional filters for supported review surfaces. |
|
|
51
65
|
| now | integer | no | Optional evaluation timestamp for time-sensitive views. |
|
|
52
66
|
|
|
53
|
-
|
|
67
|
+
### inspect_questlog_item
|
|
54
68
|
|
|
55
69
|
Inspect one specific questlog item in depth and return its richer structured detail and important related refs.
|
|
56
70
|
|
|
@@ -66,7 +80,7 @@ Read-only.
|
|
|
66
80
|
| detailLevel | string | no | compact, full. How much detail to return. |
|
|
67
81
|
| now | integer | no | Optional evaluation timestamp for time-sensitive detail. |
|
|
68
82
|
|
|
69
|
-
|
|
83
|
+
### capture_rumor
|
|
70
84
|
|
|
71
85
|
Capture uncertain incoming work as a rumor so it can be triaged later without prematurely turning it into committed execution.
|
|
72
86
|
|
|
@@ -82,7 +96,7 @@ Writes: writes_state.
|
|
|
82
96
|
| details | string | no | Optional supporting context that explains why the rumor might matter. |
|
|
83
97
|
| now | integer | no | Optional creation timestamp for the rumor. |
|
|
84
98
|
|
|
85
|
-
|
|
99
|
+
### shape_work
|
|
86
100
|
|
|
87
101
|
Create a quest (with timing, tags, and objective in one call), create a questline, settle a rumor into concrete work, or manage quest-questline membership. Use create_quest for clear commitments — include tags and timing directly to avoid follow-up calls.
|
|
88
102
|
|
|
@@ -107,7 +121,7 @@ Writes: writes_state.
|
|
|
107
121
|
| title | string | no | New title for the update_rumor action. |
|
|
108
122
|
| details | string | no | New or enriched context text for the update_rumor action. |
|
|
109
123
|
|
|
110
|
-
|
|
124
|
+
### plan_quest
|
|
111
125
|
|
|
112
126
|
Refine a quest by revising its objective before actual start or by changing its temporal planning fields.
|
|
113
127
|
|
|
@@ -130,7 +144,7 @@ Writes: writes_state.
|
|
|
130
144
|
| estimateSeconds | integer | no | Optional active-effort estimate in seconds. |
|
|
131
145
|
| now | integer | no | Optional update timestamp. |
|
|
132
146
|
|
|
133
|
-
|
|
147
|
+
### run_quest
|
|
134
148
|
|
|
135
149
|
Run quest lifecycle actions such as starting, logging effort, finishing, abandoning, or abandoning and spawning follow-up quests atomically.
|
|
136
150
|
|
|
@@ -152,7 +166,7 @@ Writes: writes_state.
|
|
|
152
166
|
| resolvedAt | integer | no | Optional resolved timestamp for finish or abandon actions. |
|
|
153
167
|
| followups | array | no | Follow-up quests to create atomically. Required for abandon_and_spawn_followups. |
|
|
154
168
|
|
|
155
|
-
|
|
169
|
+
### organize_work
|
|
156
170
|
|
|
157
171
|
Organize grouping and dependency structure by updating questlines or changing hard unlock prerequisites between concrete quests.
|
|
158
172
|
|
|
@@ -176,7 +190,7 @@ Writes: writes_state.
|
|
|
176
190
|
| fromQuestIds | array | no | Full prerequisite quest id set. |
|
|
177
191
|
| now | integer | no | Optional timestamp. |
|
|
178
192
|
|
|
179
|
-
|
|
193
|
+
### manage_repeatable
|
|
180
194
|
|
|
181
195
|
Manage recurring work definitions by creating, updating, previewing, spawning, or archiving repeatable quests.
|
|
182
196
|
|
|
@@ -205,7 +219,7 @@ Writes: writes_state.
|
|
|
205
219
|
| archivedAt | integer | no | Optional archive timestamp. |
|
|
206
220
|
| now | integer | no | Evaluation or update timestamp. |
|
|
207
221
|
|
|
208
|
-
|
|
222
|
+
### tag_work
|
|
209
223
|
|
|
210
224
|
Classify work by adding, removing, or replacing tags on quests and by replacing the future tag template set on repeatable quests.
|
|
211
225
|
|
|
@@ -222,7 +236,7 @@ Writes: writes_state.
|
|
|
222
236
|
| tagNames | array | yes | Tag names to add, remove, or replace. |
|
|
223
237
|
| now | integer | no | Optional timestamp for the tag mutation. |
|
|
224
238
|
|
|
225
|
-
|
|
239
|
+
### reward_work
|
|
226
240
|
|
|
227
241
|
Manage rewards by adding, updating, removing, or claiming quest rewards, or by replacing future reward templates on repeatable quests.
|
|
228
242
|
|
|
@@ -241,7 +255,7 @@ Writes: writes_state.
|
|
|
241
255
|
| claimedAt | integer | no | Optional claim timestamp. |
|
|
242
256
|
| now | integer | no | Optional timestamp for removal or template replacement. |
|
|
243
257
|
|
|
244
|
-
|
|
258
|
+
### retire_work
|
|
245
259
|
|
|
246
260
|
Hide an item from normal active operation without rewriting history by soft-deleting a rumor, quest, questline, or repeatable quest.
|
|
247
261
|
|
|
@@ -257,7 +271,7 @@ Writes: writes_state.
|
|
|
257
271
|
| target | object | yes | The target to hide. |
|
|
258
272
|
| deletedAt | integer | no | Optional timestamp to record when the item became hidden. |
|
|
259
273
|
|
|
260
|
-
|
|
274
|
+
### Workflow guides
|
|
261
275
|
|
|
262
276
|
- [archive-delete-and-prune](references/archive-delete-and-prune.md): Choose the right retirement action for each kind of work so history stays honest and hiding does not get confused with archival or terminal execution truth.
|
|
263
277
|
- [choose-work-shape](references/choose-work-shape.md): Choose the right structure for new work by separating uncertainty, one-shot execution, multi-step arcs, and recurring patterns.
|
|
@@ -285,7 +299,7 @@ Writes: writes_state.
|
|
|
285
299
|
- [settle-rumor-into-structure](references/settle-rumor-into-structure.md): Turn a ready rumor into committed quest or questline structure without losing provenance or pretending vague intake is settled.
|
|
286
300
|
- [tag-and-filter-portfolios](references/tag-and-filter-portfolios.md): Use tags for cross-cutting classification and portfolio filtering without confusing tags for status, timing, or dependency modeling.
|
|
287
301
|
|
|
288
|
-
|
|
302
|
+
### Principles
|
|
289
303
|
|
|
290
304
|
- Store the least committed truth first.
|
|
291
305
|
- Read before you prescribe.
|