@synap-core/cli 1.13.0 → 1.13.1-next.20261102.4b45534
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 +13 -3
- package/dist/build-info.json +2 -3
- package/dist/commands/agents.js +12 -2
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/capability.d.ts +86 -0
- package/dist/commands/capability.js +117 -30
- package/dist/commands/capability.js.map +1 -1
- package/dist/commands/data-extra.d.ts +13 -0
- package/dist/commands/data-extra.js +23 -2
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/doctor.d.ts +18 -0
- package/dist/commands/doctor.js +28 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +4 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys-request.d.ts +48 -0
- package/dist/commands/keys-request.js +236 -0
- package/dist/commands/keys-request.js.map +1 -0
- package/dist/commands/keys-request.test.d.ts +1 -0
- package/dist/commands/keys-request.test.js +176 -0
- package/dist/commands/keys-request.test.js.map +1 -0
- package/dist/commands/knowledge.d.ts +6 -0
- package/dist/commands/knowledge.js +9 -1
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/market.d.ts +74 -6
- package/dist/commands/market.js +162 -53
- package/dist/commands/market.js.map +1 -1
- package/dist/commands/mcp.d.ts +1 -1
- package/dist/commands/mcp.js +14 -9
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/pods.js +6 -2
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.js +7 -1
- package/dist/commands/proposals-actions.js.map +1 -1
- package/dist/commands/providers.d.ts +22 -6
- package/dist/commands/providers.js +39 -32
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/raycast.d.ts +15 -0
- package/dist/commands/raycast.js +36 -10
- package/dist/commands/raycast.js.map +1 -1
- package/dist/commands/status.js +12 -6
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.backoff.test.js +13 -3
- package/dist/commands/statusline.backoff.test.js.map +1 -1
- package/dist/commands/statusline.d.ts +104 -9
- package/dist/commands/statusline.js +392 -148
- package/dist/commands/statusline.js.map +1 -1
- package/dist/commands/statusline.line2.test.d.ts +15 -0
- package/dist/commands/statusline.line2.test.js +226 -0
- package/dist/commands/statusline.line2.test.js.map +1 -0
- package/dist/commands/statusline.needs-you.test.d.ts +1 -0
- package/dist/commands/statusline.needs-you.test.js +17 -0
- package/dist/commands/statusline.needs-you.test.js.map +1 -0
- package/dist/commands/statusline.now.test.d.ts +10 -0
- package/dist/commands/statusline.now.test.js +250 -0
- package/dist/commands/statusline.now.test.js.map +1 -0
- package/dist/commands/tracks.d.ts +1 -0
- package/dist/commands/tracks.js +4 -0
- package/dist/commands/tracks.js.map +1 -1
- package/dist/commands/upload.js +12 -0
- package/dist/commands/upload.js.map +1 -1
- package/dist/commands/wait.d.ts +124 -0
- package/dist/commands/wait.js +384 -0
- package/dist/commands/wait.js.map +1 -0
- package/dist/commands/wait.test.d.ts +8 -0
- package/dist/commands/wait.test.js +308 -0
- package/dist/commands/wait.test.js.map +1 -0
- package/dist/commands/worker-github-app.d.ts +63 -0
- package/dist/commands/worker-github-app.js +161 -0
- package/dist/commands/worker-github-app.js.map +1 -0
- package/dist/commands/worker-github-app.test.d.ts +1 -0
- package/dist/commands/worker-github-app.test.js +102 -0
- package/dist/commands/worker-github-app.test.js.map +1 -0
- package/dist/commands/worker-github-broker.d.ts +39 -0
- package/dist/commands/worker-github-broker.js +106 -0
- package/dist/commands/worker-github-broker.js.map +1 -0
- package/dist/commands/worker-github-broker.test.d.ts +1 -0
- package/dist/commands/worker-github-broker.test.js +90 -0
- package/dist/commands/worker-github-broker.test.js.map +1 -0
- package/dist/commands/worker-runs.test.d.ts +1 -0
- package/dist/commands/worker-runs.test.js +150 -0
- package/dist/commands/worker-runs.test.js.map +1 -0
- package/dist/commands/worker-worktrees.d.ts +34 -0
- package/dist/commands/worker-worktrees.js +87 -0
- package/dist/commands/worker-worktrees.js.map +1 -0
- package/dist/commands/worker.d.ts +192 -5
- package/dist/commands/worker.js +467 -45
- package/dist/commands/worker.js.map +1 -1
- package/dist/commands/worker.test.js +269 -3
- package/dist/commands/worker.test.js.map +1 -1
- package/dist/index.js +59 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/agents-config.d.ts +9 -0
- package/dist/lib/agents-config.js +20 -0
- package/dist/lib/agents-config.js.map +1 -1
- package/dist/lib/atomic-file.d.ts +20 -1
- package/dist/lib/atomic-file.js +100 -2
- package/dist/lib/atomic-file.js.map +1 -1
- package/dist/lib/auth.d.ts +25 -0
- package/dist/lib/auth.js +49 -9
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/box/job-server.js +4 -0
- package/dist/lib/box/job-server.js.map +1 -1
- package/dist/lib/bridge-invocation.test.d.ts +1 -0
- package/dist/lib/bridge-invocation.test.js +75 -0
- package/dist/lib/bridge-invocation.test.js.map +1 -0
- package/dist/lib/bridge-status.d.ts +144 -0
- package/dist/lib/bridge-status.js +227 -0
- package/dist/lib/bridge-status.js.map +1 -0
- package/dist/lib/bridge-status.test.d.ts +6 -0
- package/dist/lib/bridge-status.test.js +197 -0
- package/dist/lib/bridge-status.test.js.map +1 -0
- package/dist/lib/client-header.test.js +19 -1
- package/dist/lib/client-header.test.js.map +1 -1
- package/dist/lib/conversation-headers.d.ts +67 -2
- package/dist/lib/conversation-headers.js +122 -6
- package/dist/lib/conversation-headers.js.map +1 -1
- package/dist/lib/conversation-headers.test.d.ts +1 -0
- package/dist/lib/conversation-headers.test.js +78 -0
- package/dist/lib/conversation-headers.test.js.map +1 -0
- package/dist/lib/credential-class.d.ts +12 -1
- package/dist/lib/credential-class.js +20 -0
- package/dist/lib/credential-class.js.map +1 -1
- package/dist/lib/device-connect.d.ts +45 -0
- package/dist/lib/device-connect.js +60 -0
- package/dist/lib/device-connect.js.map +1 -1
- package/dist/lib/goal-words.js +6 -3
- package/dist/lib/goal-words.js.map +1 -1
- package/dist/lib/hub-client.d.ts +59 -1
- package/dist/lib/hub-client.js +130 -36
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/key-locations.d.ts +3 -3
- package/dist/lib/key-locations.js +3 -39
- package/dist/lib/key-locations.js.map +1 -1
- package/dist/lib/machine-instance.d.ts +7 -5
- package/dist/lib/machine-instance.js +7 -5
- package/dist/lib/machine-instance.js.map +1 -1
- package/dist/lib/mcp-bridge.d.ts +43 -0
- package/dist/lib/mcp-bridge.js +199 -11
- package/dist/lib/mcp-bridge.js.map +1 -1
- package/dist/lib/mcp-bridge.test.js +194 -2
- package/dist/lib/mcp-bridge.test.js.map +1 -1
- package/dist/lib/mcp-call.d.ts +5 -1
- package/dist/lib/mcp-call.js +7 -6
- package/dist/lib/mcp-call.js.map +1 -1
- package/dist/lib/mcp-connector-url.test.d.ts +1 -0
- package/dist/lib/mcp-connector-url.test.js +13 -0
- package/dist/lib/mcp-connector-url.test.js.map +1 -0
- package/dist/lib/mcp-snippets.d.ts +16 -0
- package/dist/lib/mcp-snippets.js +20 -2
- package/dist/lib/mcp-snippets.js.map +1 -1
- package/dist/lib/now-line.d.ts +66 -0
- package/dist/lib/now-line.js +193 -0
- package/dist/lib/now-line.js.map +1 -0
- package/dist/lib/now-line.test.d.ts +5 -0
- package/dist/lib/now-line.test.js +177 -0
- package/dist/lib/now-line.test.js.map +1 -0
- package/dist/lib/package-updates.d.ts +66 -0
- package/dist/lib/package-updates.js +76 -0
- package/dist/lib/package-updates.js.map +1 -0
- package/dist/lib/pod.d.ts +0 -4
- package/dist/lib/pod.js +0 -7
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/register-claude-code-mcp.test.js +19 -0
- package/dist/lib/register-claude-code-mcp.test.js.map +1 -1
- package/dist/lib/safe-open.d.ts +5 -3
- package/dist/lib/safe-open.js +9 -8
- package/dist/lib/safe-open.js.map +1 -1
- package/dist/lib/self-host.d.ts +17 -0
- package/dist/lib/self-host.js +24 -0
- package/dist/lib/self-host.js.map +1 -0
- package/dist/lib/targets.d.ts +31 -0
- package/dist/lib/targets.js +100 -104
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/term.d.ts +24 -0
- package/dist/lib/term.js +52 -0
- package/dist/lib/term.js.map +1 -0
- package/dist/lib/term.test.d.ts +1 -0
- package/dist/lib/term.test.js +29 -0
- package/dist/lib/term.test.js.map +1 -0
- package/dist/lib/transcript-index.d.ts +94 -0
- package/dist/lib/transcript-index.js +321 -0
- package/dist/lib/transcript-index.js.map +1 -0
- package/dist/lib/transcript-index.test.d.ts +10 -0
- package/dist/lib/transcript-index.test.js +200 -0
- package/dist/lib/transcript-index.test.js.map +1 -0
- package/dist/lib/wait-help.d.ts +11 -0
- package/dist/lib/wait-help.js +25 -0
- package/dist/lib/wait-help.js.map +1 -0
- package/dist/lib/wait-state.d.ts +57 -0
- package/dist/lib/wait-state.js +114 -0
- package/dist/lib/wait-state.js.map +1 -0
- package/package.json +2 -2
- package/skills/synap/SKILL.md +71 -38
- package/skills/synap/code-skills.md +15 -1
- package/skills/synap/concepts.md +36 -26
- package/skills/synap/document-embeds.md +15 -1
- package/skills/synap/focus-sessions.md +4 -4
- package/skills/synap/from-intent.md +2 -2
- package/skills/synap/governance-rules.md +2 -0
- package/skills/synap/reflexes.md +4 -4
- package/skills/synap/work-model.md +1 -1
- package/skills/synap/writing-titles.md +7 -0
- package/skills/synap-app/SKILL.md +2 -2
- package/skills/synap-app/overview.md +2 -2
- package/skills/synap-market/SKILL.md +1 -1
- package/skills/synap-market/governance-and-catalog.md +1 -1
- package/skills/synap-schema/SKILL.md +4 -1
- package/skills/synap-schema/intent-vocabulary-ssot.md +4 -1
- package/dist/commands/template.d.ts +0 -42
- package/dist/commands/template.js +0 -191
- package/dist/commands/template.js.map +0 -1
- package/dist/lib/browser-auth.d.ts +0 -35
- package/dist/lib/browser-auth.js +0 -170
- package/dist/lib/browser-auth.js.map +0 -1
- package/dist/lib/openclaw.d.ts +0 -32
- package/dist/lib/openclaw.js +0 -165
- package/dist/lib/openclaw.js.map +0 -1
- package/dist/lib/seed.d.ts +0 -13
- package/dist/lib/seed.js +0 -135
- package/dist/lib/seed.js.map +0 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The state files `synap wait` writes, and the status line reads.
|
|
3
|
+
*
|
|
4
|
+
* One file per wait: `~/.synap/waits/<conversation>/<id>.json`, where the
|
|
5
|
+
* conversation is the Claude Code session id the wait ran under
|
|
6
|
+
* (`CLAUDE_CODE_SESSION_ID`, set in every Bash command an agent runs) or
|
|
7
|
+
* `_nosession`. The wait rewrites its file after every probe (tmp + rename,
|
|
8
|
+
* so a reader never sees half a file); the status line only ever reads.
|
|
9
|
+
*
|
|
10
|
+
* Local files only, no network: the status line renders from these.
|
|
11
|
+
*/
|
|
12
|
+
export type WaitKind = "devbox" | "pr" | "run";
|
|
13
|
+
/** A wait is over once it carries `exitCode` (and `finishedAt`); `error` can be either. */
|
|
14
|
+
export type WaitState = "pending" | "queued" | "running" | "passed" | "failed" | "infra" | "error" | "timeout";
|
|
15
|
+
export declare function isFinal(w: Pick<WaitRecord, "exitCode">): boolean;
|
|
16
|
+
export interface WaitRecord {
|
|
17
|
+
id: string;
|
|
18
|
+
kind: WaitKind;
|
|
19
|
+
/** Normalised target: the devbox job name, `owner/repo#n`, `owner/repo run <id>`. */
|
|
20
|
+
ref: string;
|
|
21
|
+
label: string;
|
|
22
|
+
pid: number;
|
|
23
|
+
startedAt: number;
|
|
24
|
+
probedAt: number;
|
|
25
|
+
changedAt: number;
|
|
26
|
+
state: WaitState;
|
|
27
|
+
detail: string;
|
|
28
|
+
/** 1 + the earlier waits in this conversation for the same kind+ref: the "looping" signal. */
|
|
29
|
+
attempt: number;
|
|
30
|
+
probeErrors: number;
|
|
31
|
+
exitCode?: number;
|
|
32
|
+
finishedAt?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare function waitsRoot(): string;
|
|
35
|
+
/** A session id as a directory name: anything outside [A-Za-z0-9_-] is dropped. */
|
|
36
|
+
export declare function safeSessionDir(sessionId: string | undefined): string;
|
|
37
|
+
export declare function waitsDir(sessionId: string | undefined): string;
|
|
38
|
+
/** Every readable wait file of one conversation. A file that does not parse is skipped. */
|
|
39
|
+
export declare function readWaits(sessionId: string | undefined): WaitRecord[];
|
|
40
|
+
/** Atomic: write a sibling tmp file, then rename it over the target. */
|
|
41
|
+
export declare function writeWait(sessionId: string | undefined, rec: WaitRecord): void;
|
|
42
|
+
/** 1 + the earlier waits (any state) in this conversation for the same kind+ref. */
|
|
43
|
+
export declare function attemptFor(existing: WaitRecord[], kind: WaitKind, ref: string): number;
|
|
44
|
+
/**
|
|
45
|
+
* Remove waits that finished more than 24 h ago, and non-final ones whose
|
|
46
|
+
* process is gone and whose last probe is that old. Best-effort.
|
|
47
|
+
*/
|
|
48
|
+
export declare function pruneWaits(sessionId: string | undefined, now?: number): void;
|
|
49
|
+
export declare function pidAlive(pid: number): boolean;
|
|
50
|
+
/** How a wait is named on screen: its label, else kind + target without the Synap-core owner. */
|
|
51
|
+
export declare function waitName(w: Pick<WaitRecord, "kind" | "ref" | "label">): string;
|
|
52
|
+
/**
|
|
53
|
+
* A state and its detail in one phrase, never saying the state twice:
|
|
54
|
+
* "running (be-file · 1/2 done)", but "queued 2nd (light)" and
|
|
55
|
+
* "Release gate running · 2/4 done" as they are.
|
|
56
|
+
*/
|
|
57
|
+
export declare function stateAndDetail(state: string, detail: string): string;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The state files `synap wait` writes, and the status line reads.
|
|
3
|
+
*
|
|
4
|
+
* One file per wait: `~/.synap/waits/<conversation>/<id>.json`, where the
|
|
5
|
+
* conversation is the Claude Code session id the wait ran under
|
|
6
|
+
* (`CLAUDE_CODE_SESSION_ID`, set in every Bash command an agent runs) or
|
|
7
|
+
* `_nosession`. The wait rewrites its file after every probe (tmp + rename,
|
|
8
|
+
* so a reader never sees half a file); the status line only ever reads.
|
|
9
|
+
*
|
|
10
|
+
* Local files only, no network: the status line renders from these.
|
|
11
|
+
*/
|
|
12
|
+
import fs from "node:fs";
|
|
13
|
+
import os from "node:os";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
export function isFinal(w) {
|
|
16
|
+
return typeof w.exitCode === "number";
|
|
17
|
+
}
|
|
18
|
+
const PRUNE_AFTER_MS = 24 * 60 * 60_000;
|
|
19
|
+
export function waitsRoot() {
|
|
20
|
+
return path.join(os.homedir(), ".synap", "waits");
|
|
21
|
+
}
|
|
22
|
+
/** A session id as a directory name: anything outside [A-Za-z0-9_-] is dropped. */
|
|
23
|
+
export function safeSessionDir(sessionId) {
|
|
24
|
+
const clean = (sessionId ?? "").replace(/[^A-Za-z0-9_-]/g, "");
|
|
25
|
+
return clean || "_nosession";
|
|
26
|
+
}
|
|
27
|
+
export function waitsDir(sessionId) {
|
|
28
|
+
return path.join(waitsRoot(), safeSessionDir(sessionId));
|
|
29
|
+
}
|
|
30
|
+
/** Every readable wait file of one conversation. A file that does not parse is skipped. */
|
|
31
|
+
export function readWaits(sessionId) {
|
|
32
|
+
const dir = waitsDir(sessionId);
|
|
33
|
+
let names;
|
|
34
|
+
try {
|
|
35
|
+
names = fs.readdirSync(dir);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const n of names) {
|
|
42
|
+
if (!n.endsWith(".json"))
|
|
43
|
+
continue;
|
|
44
|
+
try {
|
|
45
|
+
const rec = JSON.parse(fs.readFileSync(path.join(dir, n), "utf-8"));
|
|
46
|
+
if (rec && typeof rec.id === "string" && typeof rec.state === "string")
|
|
47
|
+
out.push(rec);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* a file mid-write by an older writer, or not ours */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** Atomic: write a sibling tmp file, then rename it over the target. */
|
|
56
|
+
export function writeWait(sessionId, rec) {
|
|
57
|
+
const dir = waitsDir(sessionId);
|
|
58
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
59
|
+
const target = path.join(dir, `${rec.id}.json`);
|
|
60
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
61
|
+
fs.writeFileSync(tmp, JSON.stringify(rec));
|
|
62
|
+
fs.renameSync(tmp, target);
|
|
63
|
+
}
|
|
64
|
+
/** 1 + the earlier waits (any state) in this conversation for the same kind+ref. */
|
|
65
|
+
export function attemptFor(existing, kind, ref) {
|
|
66
|
+
return 1 + existing.filter((w) => w.kind === kind && w.ref === ref).length;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Remove waits that finished more than 24 h ago, and non-final ones whose
|
|
70
|
+
* process is gone and whose last probe is that old. Best-effort.
|
|
71
|
+
*/
|
|
72
|
+
export function pruneWaits(sessionId, now = Date.now()) {
|
|
73
|
+
const dir = waitsDir(sessionId);
|
|
74
|
+
for (const w of readWaits(sessionId)) {
|
|
75
|
+
const old = isFinal(w)
|
|
76
|
+
? now - (w.finishedAt ?? w.probedAt) > PRUNE_AFTER_MS
|
|
77
|
+
: now - w.probedAt > PRUNE_AFTER_MS && !pidAlive(w.pid);
|
|
78
|
+
if (!old)
|
|
79
|
+
continue;
|
|
80
|
+
try {
|
|
81
|
+
fs.unlinkSync(path.join(dir, `${w.id}.json`));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* already gone */
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function pidAlive(pid) {
|
|
89
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
90
|
+
return false;
|
|
91
|
+
try {
|
|
92
|
+
process.kill(pid, 0);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
// EPERM: the process exists, it is just not ours to signal.
|
|
97
|
+
return e.code === "EPERM";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** How a wait is named on screen: its label, else kind + target without the Synap-core owner. */
|
|
101
|
+
export function waitName(w) {
|
|
102
|
+
return w.label || `${w.kind} ${w.ref.replace(/^Synap-core\//, "")}`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A state and its detail in one phrase, never saying the state twice:
|
|
106
|
+
* "running (be-file · 1/2 done)", but "queued 2nd (light)" and
|
|
107
|
+
* "Release gate running · 2/4 done" as they are.
|
|
108
|
+
*/
|
|
109
|
+
export function stateAndDetail(state, detail) {
|
|
110
|
+
if (!detail)
|
|
111
|
+
return state;
|
|
112
|
+
return new RegExp(`\\b${state}\\b`).test(detail) ? detail : `${state} (${detail})`;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=wait-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-state.js","sourceRoot":"","sources":["../../src/lib/wait-state.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synap-core/cli",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.1-next.20261102.4b45534",
|
|
4
4
|
"description": "Connect any AI agent (Claude Code, Codex, Cursor and more) to your own Synap data pod: shared memory, structured data and human-approved changes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@synap-core/hub-rest-client": "^1.1.1",
|
|
22
|
-
"@synap-core/types": "^1.12.
|
|
22
|
+
"@synap-core/types": "^1.12.4",
|
|
23
23
|
"@synap-core/workspace-templates": ">=0.12.0 <1.0.0",
|
|
24
24
|
"chalk": "^5.4.0",
|
|
25
25
|
"commander": "^13.0.0",
|
package/skills/synap/SKILL.md
CHANGED
|
@@ -43,13 +43,13 @@ Your job is to turn unstructured input into a **connected** knowledge graph. Iso
|
|
|
43
43
|
|
|
44
44
|
The user's Synap pod: source of truth. Tool names below are stems; your door may prefix them (`pod__ask`).
|
|
45
45
|
|
|
46
|
-
1. **Recall first.**
|
|
47
|
-
2. **Capture
|
|
48
|
-
3. **Orient once.** `orient`: pending review
|
|
46
|
+
1. **Recall first.** `get_*` a known id, else `ask`.
|
|
47
|
+
2. **Capture as you go.** A decision, learning, pain (`finding`), win (`proof-point`), fact or task: `capture` it when it happens; about the user: `remember_fact`.
|
|
48
|
+
3. **Orient once.** `orient`: pending review, open sessions.
|
|
49
49
|
4. **Work in a session.** `start_session` or resume (playbook `templateId`); goal (TRACK): `list_tracks`, else `start_track`; work in it = `start_session` + `trackId`; 2-5 `criteria`; status moves carry `expectedStatus`; person-only: `owner:'human'` slot + `blockedReason` + `ask` (confirm/choose with 1 `recommended`/form/act/provide), then `wait_for_answer` if listed; post progress, questions and results in its room (`post_message` to `session.channelId`); your own chat may repeat them (`Q-<id8>`); chat answer → `relay_answer`, words verbatim; PR = outcome `pr-<repo>-<n>` (`ref.url`); `evaluate_session`, close open asks, `complete_session`.
|
|
50
50
|
5. **Never guess a project**: pin only what the user names (`set_*_focus`).
|
|
51
51
|
6. **`proposed` is success**: keep going, never retry.
|
|
52
|
-
7. **Discover before inventing**: `list_profiles` / `list_capabilities`; **extend
|
|
52
|
+
7. **Discover before inventing**: `list_profiles` / `list_capabilities`; **extend**, never a twin.
|
|
53
53
|
8. **One space per domain**; projects filter it (`file_into_project`, `project_use_workspace`).
|
|
54
54
|
|
|
55
55
|
Depth: `load_skill` `system/synap/concepts`, `work-model`, `focus-sessions`, `from-intent`, `escalation-ladder`, `writes`.
|
|
@@ -60,32 +60,42 @@ Depth: `load_skill` `system/synap/concepts`, `work-model`, `focus-sessions`, `fr
|
|
|
60
60
|
|
|
61
61
|
The ONE glossary; other skills point here. Word = what the user sees; internal = tools and tables.
|
|
62
62
|
|
|
63
|
-
| Word | Internal | Answers
|
|
64
|
-
| ------------------- | ----------------------- |
|
|
65
|
-
| **Space** | workspace | which domain: kinds + tools?
|
|
66
|
-
| **Project** | project | what am I committed to, with whom?
|
|
67
|
-
| **Goal** | project_tracks | what goal am I pursuing?
|
|
68
|
-
| **Step** | stage | where does this work stand?
|
|
69
|
-
| **Work** | focus_session | what am I doing this sitting?
|
|
70
|
-
| **Template** | playbook | how do I reuse it?
|
|
71
|
-
| **Pack** | suite | which templates come together?
|
|
72
|
-
| **Rule** |
|
|
73
|
-
| **
|
|
74
|
-
| **
|
|
75
|
-
| **
|
|
76
|
-
| **
|
|
77
|
-
| **
|
|
78
|
-
| **
|
|
79
|
-
| **
|
|
80
|
-
| **
|
|
81
|
-
| **
|
|
82
|
-
| **
|
|
83
|
-
| **
|
|
84
|
-
| **
|
|
85
|
-
| **
|
|
86
|
-
| **
|
|
87
|
-
| **
|
|
88
|
-
| **
|
|
63
|
+
| Word | Internal | Answers | Test · e.g. · not |
|
|
64
|
+
| ------------------- | ----------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| **Space** | workspace | which domain: kinds + tools? | owns kinds, never done · CRM · not a project or method; findable, not emphasised |
|
|
66
|
+
| **Project** | project | what am I committed to, with whom? | ends with the commitment; spans spaces · a launch · not a task, method, or the owner's company |
|
|
67
|
+
| **Goal** | project_tracks | what goal am I pursuing? | in ONE project; open while it matters, or its judge closes it with a verdict; criteria say when it is done; work = sessions · grow the newsletter · tools say "track" |
|
|
68
|
+
| **Step** | stage | where does this work stand? | = the subject's status: move the thing, the step follows · legacy: steps of a goal started from a method |
|
|
69
|
+
| **Work** | focus_session | what am I doing this sitting? | one aim · no noun: "Start work" |
|
|
70
|
+
| **Template** | playbook | how do I reuse it? | kind DERIVED, never declared: scope session = work template (a method a session or worker follows), project = goal template (legacy); also space and automation templates |
|
|
71
|
+
| **Pack** | suite | which templates come together? | a bundle; depends on space templates, never creates a space |
|
|
72
|
+
| **Rule** | skill rule | what do my agents always follow? | a standing instruction written for agents · "always cite sources" · not an Automation, not Approvals |
|
|
73
|
+
| **Automation** | automation | what runs by itself, when? | standing · "every Monday…" · not a Rule, not Approvals |
|
|
74
|
+
| **Approvals** | governance rules | which AI writes wait for me? | decides review vs auto, does no work |
|
|
75
|
+
| **Tools** | capability, skill, tool | what can it act with? | one word; the detail shows the kind |
|
|
76
|
+
| **Card** | cell | what block did I make? | the made UI block · "a deals summary" · never Cell, Widget or Interface |
|
|
77
|
+
| **Display** | renderer | how does this kind look? | a card bound to a kind's slot · "Change display" · Renderer stays an engine word |
|
|
78
|
+
| **View** | view | how do I look at the data? | a saved arrangement of things · a table, a board · not a Card |
|
|
79
|
+
| **App** | built-in surface | what do I open in Synap? | CRM, Calendar, a space's own front end · never a space, never outside software |
|
|
80
|
+
| **Connected app** | application | which outside software holds a grant? | reaches the pod with a grant · not an App |
|
|
81
|
+
| **Account** | provider connection | which of my accounts is linked? | a person's link to an outside service · never Connection, Connector or Integration |
|
|
82
|
+
| **Kind** | profile | what shape does a thing have? | its fields and status list · never Data type, Schema or Profile |
|
|
83
|
+
| **Make** | destination | where do I make things? | a view, a card, a space, an automation · pairs with Work |
|
|
84
|
+
| **Get more** | destination | where do I add more? | the store · never Marketplace or Get more tools |
|
|
85
|
+
| **To review** | proposal | what awaits my approval? | `proposed` is success |
|
|
86
|
+
| **Role** | role profile + facet | which hat does it wear? | one role per name, pod-wide; spaces add properties by overlay; its entities show in all · client · never a twin |
|
|
87
|
+
| **Thing** | entity | what is being worked on? | one kind, maybe roles · a post, a lead · never a twin for a hat |
|
|
88
|
+
| **Status** | lifecycle | where does it stand? | ONE list per kind or role, declared on its profile; category open·active·paused·done·lost · moved only through the door (`expectedStatus`) |
|
|
89
|
+
| **Pipeline** | pipeline view | what is in each status? | computed from a lifecycle, never created · not an object |
|
|
90
|
+
| **Worker** | playbook activator | what starts work by itself? | a method + trigger (enters status · schedule · count · manual) + size (per thing · per batch); a goal or project turns it on |
|
|
91
|
+
| **Inbox** | needs-you signals | what needs me? | one list: decisions, questions, routine changes, broken · not Work |
|
|
92
|
+
| **Questions** | owed slot ask | what did an agent ask me? | an Inbox filter · answer it, the work resumes |
|
|
93
|
+
| **Routine changes** | reversible proposal | what can I approve in a batch? | an Inbox filter · only reversible changes batch; undo says what it cannot restore |
|
|
94
|
+
| **Broken** | failed or stuck work | what needs a fix? | an Inbox filter · a failed run, a stuck session |
|
|
95
|
+
| **Library** | data (things, files) | what did we bring in? | what you and your agents kept or made: things, files, imports · not a space |
|
|
96
|
+
| **Unfiled** | entity in no project | what is not filed yet? | things outside every project · file them into one |
|
|
97
|
+
| **Agents** | agent users + keys | who acts for me? | Claude Code, Codex, any MCP client; each has its own page · not a Tool |
|
|
98
|
+
| **Getting started** | first-run Home card | what do I try first? | goes away once done |
|
|
89
99
|
|
|
90
100
|
Doors: `start_track`, `start_session`, `create_rule`, `attach_facet`, `update_entity` + `expectedStatus` (a status). How they fit (sizes, workers, tenses): `work-model`.
|
|
91
101
|
|
|
@@ -150,7 +160,7 @@ A worker is a playbook **activator**, declared on the method and owned by the li
|
|
|
150
160
|
|
|
151
161
|
### Goals (tracks)
|
|
152
162
|
|
|
153
|
-
A goal is a _track_ in every tool and field name (`start_track`, `trackId`) — say "goal" to the person; a session's one-line `goal` is its **Aim**. A goal holds an owner, a direction, instructions, the workers it turns on, and what done means (criteria, or a number measured as transitions into `done`). It has no stages. A goal can stay open as long as it matters, or finish: a person closes it with a verdict once its criteria are met (`set_track_status` `completed` + `verdict`; dropped = `archived`, with a `verdict` saying why). Your close is a proposal; a closed goal comes back only as a new version. Pause it while nobody should work on it. Work in it = `start_session` + `trackId`. A thing may count for two goals. Solo users may never need one: workers can run space-wide. Legacy: `start_stage_session` and `add_track_stage` serve old goals started from a method; never `advance_track` without the user.
|
|
163
|
+
A goal is a _track_ in every tool and field name (`start_track`, `trackId`) — say "goal" to the person; a session's one-line `goal` is its **Aim**. A goal holds an owner, a direction, instructions, the workers it turns on, and what done means (criteria, or a number measured as transitions into `done`). It has no stages. A goal can stay open as long as it matters, or finish: a person closes it with a verdict once its criteria are met (`set_track_status` `completed` + `verdict`; dropped = `archived`, with a `verdict` saying why; every move sends `expectedStatus`, the status you read). Your close is a proposal; a closed goal comes back only as a new version. Pause it while nobody should work on it. Work in it = `start_session` + `trackId`. A thing may count for two goals. Solo users may never need one: workers can run space-wide. Legacy: `start_stage_session` and `add_track_stage` serve old goals started from a method; never `advance_track` without the user.
|
|
154
164
|
|
|
155
165
|
**Keep the pod current (every agent, every session)** — three rules, so the next agent picks your step up from the pod alone:
|
|
156
166
|
|
|
@@ -330,7 +340,7 @@ If a close project exists, **reuse it**. Do not mint a twin. Name-match is enoug
|
|
|
330
340
|
|
|
331
341
|
4. `synap_start_session` — **name the unit of work before you build it.** Title + goal, nothing else; the session is the room the rest of this happens in, not a form to fill. Every write you make afterwards is attributed to it automatically, so the user can open ONE object and see the whole arc instead of loose proposals with no shared story. Reuse an open session that already covers this intent (`synap_list_sessions`) rather than starting a second one. If the intent is a single fact with no structure behind it, skip the session and use the `synap` skill instead — this whole conductor is the wrong door for that.
|
|
332
342
|
|
|
333
|
-
**Propose its `criteria` — do not grade yourself without them.** Two to five binary, observable statements the person can validate or rewrite ("`list_profiles` returns the `grp-run` kind"), not "the pack is good". They may equally be written by the person; what is not allowed is neither. A session with no criteria leaves you nothing to report against but your own opinion, which is how "85% complete" gets said about work nobody can check. Criteria are declarable at `synap_start_session` (as `outcomes` with `kind: 'fact'`, or the older `criteria`) and upserted later with `synap_update_session` — a session created inside a plan carries `expectedOutputs`,
|
|
343
|
+
**Propose its `criteria` — do not grade yourself without them.** Two to five binary, observable statements the person can validate or rewrite ("`list_profiles` returns the `grp-run` kind"), not "the pack is good". They may equally be written by the person; what is not allowed is neither. A session with no criteria leaves you nothing to report against but your own opinion, which is how "85% complete" gets said about work nobody can check. Criteria are declarable at `synap_start_session` (as `outcomes` with `kind: 'fact'`, or the older `criteria`) and upserted later with `synap_update_session` — a session created inside a plan (`synap_capture` `sessions[]`) carries both: give each step its `criteria` with its `expectedOutputs`, and they land when the plan is approved.
|
|
334
344
|
|
|
335
345
|
**A discovered prerequisite is a blocking child, not a paragraph in the same session.** When the goal cannot be finished until infrastructure exists, start that infrastructure as its own session: `parentSessionId` of the goal session, plus `suspendedIntent` — one line naming what the goal was about to do. That pair links the child (`spawned_from`) and blocks the parent (`blocked_by` the child). Work the child. Do not keep building the parent goal beside it. The parent stays open and waits; when the child is validated and closed, the parent unblocks and `suspendedIntent` is what you resume. A child that is only a slice of the same goal passes `parentSessionId` alone and does not block the parent.
|
|
336
346
|
|
|
@@ -414,7 +424,7 @@ A **goal** is a _track_ in every tool and field name (`synap_start_track`, `trac
|
|
|
414
424
|
| new **kinds of things** no workspace owns | a workspace (four-test, `workspace-design`) — never to represent a goal |
|
|
415
425
|
| a new long-lived commitment with its own gravity | a project — never a twin project for a goal of an existing one |
|
|
416
426
|
|
|
417
|
-
**A goal steers; its sessions verify.** A session that passes a criterion CLAIMS it; the judge accepts or sends it back — never accept your own claim. Report a lasting goal's number with `synap_update_track` `kpi: { current }`: a STATED value, stamped with when and by whom — never invent a measurement. Reaching the target nudges the person to re-aim it or close the goal; never change the target or close the goal yourself. While a goal is active, its agent may work in the spaces its project links (`synap_project_use_workspace`); pausing it suspends that, closing or dropping it ends it. Pause, resume, close (`completed` + a `verdict`) or drop (`archived`, with a `verdict` saying why) it with `synap_set_track_status
|
|
427
|
+
**A goal steers; its sessions verify.** A session that passes a criterion CLAIMS it; the judge accepts or sends it back — never accept your own claim. Report a lasting goal's number with `synap_update_track` `kpi: { current }`: a STATED value, stamped with when and by whom — never invent a measurement. Reaching the target nudges the person to re-aim it or close the goal; never change the target or close the goal yourself. While a goal is active, its agent may work in the spaces its project links (`synap_project_use_workspace`); pausing it suspends that, closing or dropping it ends it. Pause, resume, close (`completed` + a `verdict`) or drop (`archived`, with a `verdict` saying why) it with `synap_set_track_status`, sending `expectedStatus` = the status you read (`conflict` = someone moved it: re-read, decide again); your close is a proposal the person approves. Goal writes are governed: `proposed` is success. Installing a pack onto a project does **not** start goals — start each one.
|
|
418
428
|
|
|
419
429
|
**Legacy: goals with steps.** A goal started from a goal template (`scope: "project"`, `playbookId` on `synap_start_track`) has re-enterable stages. Work a stage with `synap_start_stage_session` (`trackId`, optional `stageKey`); never `synap_advance_track` without the user — advancing returns an `offer` (show it, start it only on a yes). Do not create new goal templates; a new goal needs none.
|
|
420
430
|
|
|
@@ -985,6 +995,8 @@ Every write returns a `status` field:
|
|
|
985
995
|
"denied" → blocked, explain reason to user
|
|
986
996
|
```
|
|
987
997
|
|
|
998
|
+
**`DENIED_BY_RULE` is a person's "Never".** A refusal whose reason opens with `DENIED_BY_RULE` (a write's `reason`, a run's `reasonCode`) means the person said never for this agent and this kind of act. It was not done. Do not retry it or do it another way; ask the person if it is needed. Only a pod admin can take that back, in pod admin Settings.
|
|
999
|
+
|
|
988
1000
|
**`"proposed"` is not an error.** It's the governance system queueing your change. When you get it:
|
|
989
1001
|
|
|
990
1002
|
1. Tell the user exactly what was queued — use the `summary` field **verbatim**. Don't paraphrase.
|
|
@@ -1512,6 +1524,13 @@ claim cut off. Everything else goes elsewhere:
|
|
|
1512
1524
|
When unsure, ask: "will this still help someone in three months, and is it a
|
|
1513
1525
|
fact, a pitfall or a rule?" If not, it is not knowledge.
|
|
1514
1526
|
|
|
1527
|
+
### Descriptions of projects, spaces and goals
|
|
1528
|
+
|
|
1529
|
+
A description says what the thing **is** and who it is for. A decision is
|
|
1530
|
+
**linked, never restated**: a restated decision goes stale the day the decision
|
|
1531
|
+
changes (the Synap project description repeated the 5 Oct branding split, which
|
|
1532
|
+
a 13 Oct decision replaced). Link the `decision` entity; let it carry the rule.
|
|
1533
|
+
|
|
1515
1534
|
---
|
|
1516
1535
|
|
|
1517
1536
|
## Document embeds — live entities/views/cells inside markdown
|
|
@@ -1720,7 +1739,21 @@ Never rewrite a whole document to change part of it. Read it, then patch it:
|
|
|
1720
1739
|
- `replace_all {content}` — the whole body; needs `baseRevision` and is
|
|
1721
1740
|
always reviewed;
|
|
1722
1741
|
- `set_title {title}` — renames the document (its one title). A human name,
|
|
1723
|
-
never an id or a slug; the content is left as it is
|
|
1742
|
+
never an id or a slug; the content is left as it is;
|
|
1743
|
+
- `insert_embed {directive, ref, props?, fallback?, sectionId? | after?}` —
|
|
1744
|
+
adds an embed written for you (`synap-cell` with `{cellKey}` and its props,
|
|
1745
|
+
`synap-entity` with `{id}`, `synap-view` with `{viewId}`): prefer it to
|
|
1746
|
+
typing directive text. It goes at the end, at the end of section
|
|
1747
|
+
`sectionId`, or after the line holding `after` (exact once). Give it a
|
|
1748
|
+
`fallback` sentence: it is what the phone and exports read;
|
|
1749
|
+
- `set_scope {scope}` — what a LIVING document's cells read through:
|
|
1750
|
+
`{kind:"pod"}`, `{kind:"workspace", workspaceId, projectId?}`,
|
|
1751
|
+
`{kind:"project", projectId}`, `{kind:"track", trackId}` or
|
|
1752
|
+
`{kind:"session", sessionId}` (null clears it). Never put a scope in a
|
|
1753
|
+
cell's props: the host stamps the document's scope on every cell;
|
|
1754
|
+
- `set_refresher {automationId}` — binds the automation that refreshes the
|
|
1755
|
+
document (null unbinds). Its runs may rewrite the document's EXISTING
|
|
1756
|
+
`ai` sections without review; anything else they write is reviewed.
|
|
1724
1757
|
|
|
1725
1758
|
Refused, whatever the op: changing a section whose `owner` is `human` (the AI
|
|
1726
1759
|
never rewrites a person's words — write a new section), and removing an embed
|
|
@@ -2154,7 +2187,7 @@ A **focus session** is a named, multi-step work room where you and AI agents col
|
|
|
2154
2187
|
|
|
2155
2188
|
**Fetch the pod's processes before you invent one.** Without `templateId`, the start door hands back the pod's existing playbooks ranked against your title and goal — the response's `playbooks` block lists `candidates` (id, name, score, and the `reason` each one matched) and applies **nothing**. Read them: if one fits, start again naming it with `templateId` (the only way a playbook binds), and if none does, go ad-hoc deliberately. Pass `templateId: null` to skip matching entirely. You can also look first, with `synap_list_playbooks` / `synap_match_playbooks`.
|
|
2156
2189
|
|
|
2157
|
-
**Declare your OUTCOMES** — `outcomes: [{ key?, label, kind, verify?, owner? }]` on `synap_start_session` / `synap_update_session` (Hub: the same field on `POST`/`PATCH /focus-sessions`). One list of what the work must yield, each one verifiable. Two kinds:
|
|
2190
|
+
**Declare your OUTCOMES** — a new session you start must declare at least one fact (or a deliverable with `verify`), or the start is refused (`NO_CRITERIA`); continuing an existing one needs none. `outcomes: [{ key?, label, kind, verify?, owner? }]` on `synap_start_session` / `synap_update_session` (Hub: the same field on `POST`/`PATCH /focus-sessions`). One list of what the work must yield, each one verifiable. Two kinds:
|
|
2158
2191
|
|
|
2159
2192
|
- **A fact** (`kind: 'fact'`) — your definition of done, a binary, observable statement ("Typecheck passes with 0 errors"), checked by `verify` (`capability` → `judge` → `human`; default `judge`) through `synap_evaluate_session`. Two to five, not a checklist. **Propose them yourself and let the person validate or rewrite them**; they may equally be written by the person, but a session with none can only be reported on by opinion. Closing never blocks on them; unmet ones are flagged.
|
|
2160
2193
|
- **A deliverable** (`kind: 'document'`, `'report'`, `'code'`, `'decision'`…). **Declare what the work will produce** — the documents, entities and decisions this session owes. That list is what makes "done" derivable instead of announced, and it is what the person's board shows as still outstanding. Give each a `key` (or one is derived from the label) and name it by that key from then on.
|
|
@@ -2171,10 +2204,10 @@ On `synap_update_session`, `outcomes` UPSERTS by key — a renamed label keeps i
|
|
|
2171
2204
|
- **Targets get a result each.** A worker session holds its things as targets: your own move of a target marks it `done`, someone else's marks it `skipped`, and targets left at close are `skipped`. Put each outcome on its thing, not only in a summary. Model: `work-model`.
|
|
2172
2205
|
- **Person-only steps** are an `owner: 'human'` output with a `blockedReason` and a `why` (below) — never a line buried in your reply.
|
|
2173
2206
|
- **Room first.** Post progress, questions and results in the session room (below); your own chat may repeat them; show a question there with its short id, `Q-` + the first 8 characters of its message id (`Q-1a2b3c4d`).
|
|
2174
|
-
- **Grade before you say done.** `synap_evaluate_session { sessionId, evidence: { <criterionKey>: { passed, detail } } }` with the real evidence — the command output, the link, the count. Then close every question you asked that is still open (answer or withdraw it, below), then `synap_complete_session`: the pod refuses your close while your own room questions are undispositioned.
|
|
2207
|
+
- **Grade before you say done.** `synap_evaluate_session { sessionId, evidence: { <criterionKey>: { passed, detail } } }` with the real evidence — the command output, the link, the count. Then close every question you asked that is still open (answer or withdraw it, below), then `synap_complete_session`: the pod refuses your close while your own room questions are undispositioned. Your `closed` close is refused (`NOT_DONE`) while a required criterion you can still check is failed or ungraded, a required outcome an agent owes (yours or a delegate's) is open and unclaimed, or a required outcome the person owes is still open: then wait for them (leave the session open or pause it). What only awaits the person's grade or review (a criterion they check, one escalated to them, an outcome you claimed, a proposal pending) never refuses and comes back as `waiting`. To close anyway, pass `reason`: it is posted as one line in the session room.
|
|
2175
2208
|
- **The doors remind you.** `synap_update_session` and `synap_complete_session` replies (and Hub `PATCH /focus-sessions/:id` / `POST …/complete`) carry `nudges` (criteria still ungraded, no criteria, a stage never set, outputs owed by the person, and — once, on a session born without a playbook — the playbooks that fit it). `orient`'s `startHere.sessionsOwingGrade` lists your open sessions with ungraded criteria.
|
|
2176
2209
|
- **Goal, PR, close.** File the session into the goal it serves (`trackId`: the start reply's `offers.goals` lists the project's open goals, `offers.sessions` the open sessions already on close work — continue one of those rather than opening a twin). Record each PR as an outcome `pr-<repo>-<n>` (`kind: 'pull_request'`, `ref: { url }`; `sessionId` may be left out when this conversation has exactly one open session). When every outcome is met, the reply's `nudges.readyToClose` says so: grade, then close. `synap_get_session`'s continuation carries the `goal` (end state, criteria marks, KPI), the `siblings` (parallel, before, next) and the `workUnits` (your recorded PRs and their state).
|
|
2177
|
-
- **Keep the books: end what you started.** `orient`'s `startHere.looseEnds` lists YOUR leftovers — sessions you opened, idle over a week; asks you left owed by the person on sessions you ended; your proposals pending over a week; automations you made that never fired — each row with the call that ends it (`close`). Close your own idle session when no person touched it and it owes the person nothing. Otherwise withdraw its asks (`retireOutput`, the person confirms) or hand them over in its room first. A close that leaves asks with the person returns `leftOwed`: only a cancel retires them, so withdraw or hand over each one — never leave one owed without saying so.
|
|
2210
|
+
- **Keep the books: end what you started.** `orient`'s `startHere.looseEnds` lists YOUR leftovers — sessions you opened, idle over a week; asks you left owed by the person on sessions you ended; your proposals pending over a week; automations you made that never fired — each row with the call that ends it (`close`). Close your own idle session when no person touched it and it owes the person nothing. Archive an automation you made that never ran (`automation.archive`): it applies at once; archiving anyone else's, or one that ran, is a proposal. Otherwise withdraw its asks (`retireOutput`, the person confirms) or hand them over in its room first. A close that leaves asks with the person returns `leftOwed`: only a cancel retires them, so withdraw or hand over each one — never leave one owed without saying so.
|
|
2178
2211
|
|
|
2179
2212
|
**Hub Protocol REST** (for IS → backend; always include `workspaceId`):
|
|
2180
2213
|
|
|
@@ -2218,7 +2251,7 @@ Note: all hub-protocol writes are governance-gated server-side — a start may c
|
|
|
2218
2251
|
**Asking the person.** On an `owner: 'human'` slot, add an `ask` so they answer in one tap instead of typing:
|
|
2219
2252
|
|
|
2220
2253
|
- **Say it once.** The `label` is a short key (a few words: "Stripe account"), never the question and never "Decide: …". The `prompt` (confirm) or the options (choose) carry the question. `why` adds only what neither says: the fact that makes it matter, never a repeat of the label or prompt. Give each answer its consequence, and recommend one when you have a view. The person reads this card once and decides.
|
|
2221
|
-
- `confirm` — yes/no: `prompt` is the question; `yes` / `no` may each carry a one-line `description` of what that answer does, and ONE may be `recommended`. `choose` — 1–8 `options` (`label`, optional `value` and a one-line `description` of the consequence, at most ONE `recommended`; `allowOther:
|
|
2254
|
+
- `confirm` — yes/no: `prompt` is the question; `yes` / `no` may each carry a one-line `description` of what that answer does, and ONE may be `recommended`. `choose` — 1–8 `options` (`label`, optional `value` and a one-line `description` of the consequence, at most ONE `recommended`; the person can always answer in their own words instead; `allowOther: false` closes that, only for a choice code reads as a value). `form` — a small flat form (never a secret field). `act` — something to DO: an http(s) `url` and up to 7 `steps`. `provide` — a `connection`, `file` or `secret` handed over through the vault (you receive a reference, never the secret in the answer). A secret you asked for comes with a read for you alone, for 60 minutes: redeem the `vault://` ref (`POST /vault/redeem`). If the receipt says no agent can read it, ask for access through `POST /vault/request`.
|
|
2222
2255
|
- **Which mode.** A DECISION is `confirm` (one yes/no) or `choose` — never `act`. When you have a view, mark exactly ONE answer `recommended` (a choose option, or a confirm's `yes` / `no`): the person's pick vs your recommendation is recorded, and every answered `confirm`/`choose` files a `decision` entity automatically. Recall past decisions first (`synap_ask`) so your recommendation follows the user's past choices. Use `act` ONLY for a physical/world task with `steps` (they answer "I did this"). Always add an `ask`: a human-owned slot with only `blockedReason` + `why` shows a bare "I did this" button. Example: `ask: {"mode":"choose","options":[{"label":"Ship now","recommended":true,"description":"Publishes today"},{"label":"Wait a week"}]}`, or `ask: {"mode":"confirm","prompt":"Publish the post today?","yes":{"description":"Goes live at 9:00","recommended":true},"no":{"description":"Stays a draft"}}`.
|
|
2223
2256
|
- **How it comes back.** `act` is resolved by "I did this" (attest): the slot is done and you are woken. Every other mode goes through the answer door: the slot comes back to you with `answer.text` (a readable summary) and `answer.value`, the typed pick (`confirm` → `confirmed`, `chip` → the option, `form` → `values`, `provide` → `ref`, `text`). Act on `answer.value`, not the prose. A plain reply in the room answers a typed slot only when the ask takes text (`choose` with `allowOther`); otherwise it answers your question and the slot stays owed.
|
|
2224
2257
|
- **Then wait — don't end your turn.** After an ask, call `wait_for_answer` with the `sessionId` (when your tools list it; an in-app agent has no such tool, the answer wakes it): it returns the moment the person answers (`status: 'answered'`, `answers[]` with `text` and the typed `value`) or after `timeoutSeconds` (default 50, max 90; Codex: 55 or less) with `status: 'timeout'` and `nextSince` — call again with `since = nextSince` to keep waiting. Without `since` you get only answers you have not picked up yet. Your read marks the answer "Picked up" for the person. If you must stop, the answer stays on the slot for your next turn.
|
|
@@ -31,12 +31,22 @@ Calls an installed tool's API with ITS credential (you never see the key).
|
|
|
31
31
|
- `tool`: the tool's name, as `synap_list_capabilities` lists it (e.g. `"apify_api"`).
|
|
32
32
|
- `method`: `"GET" | "POST" | "PUT" | "DELETE"`.
|
|
33
33
|
- `path`: relative to the tool's base URL. If the base URL already ends in a version (`https://api.apify.com/v2`), do NOT repeat it: `"/acts/{actorId}/runs"`, not `"/v2/acts/…"`.
|
|
34
|
-
- `opts`: `{ headers?, baseUrlOverride? }`.
|
|
34
|
+
- `opts`: `{ headers?, baseUrlOverride?, multipart? }`.
|
|
35
35
|
|
|
36
36
|
Returns `{ status, headers, body }` on success, or `{ proposed: true, proposalId }` when the call was filed for review. It THROWS `callProvider failed: …` on a provider or auth failure. Always branch on `proposed` before reading `body`.
|
|
37
37
|
|
|
38
38
|
A GET runs inline. A POST/PUT/DELETE by an agent is governed: it proposes, UNLESS the tool is one the skill declared in `requiredTools` on `synap_create_skill`. Then the verb's own approval covers it, and the run does not stop for a second review.
|
|
39
39
|
|
|
40
|
+
### Pod files (`file:url`, `file:bytes`)
|
|
41
|
+
|
|
42
|
+
Declare a parameter as a pod file in `parameters`: `"video": "file:url"`, `"media": "file[]:url?"`, `"attachments": "file[]:bytes?"`. The caller passes the file entity's id (a list for `file[]`). An agent's run that carries a file always waits for the person's approval.
|
|
43
|
+
|
|
44
|
+
- `:url`: your code receives a signed https URL to the file. Hand it to the tool as is. It lives 15 minutes for a sync skill and 6 hours for an async one.
|
|
45
|
+
- `:bytes`: your code receives a handle (`podfile:…`), not the bytes. Put it in a `callProvider` body sent to a tool the skill declared in `requiredTools`, and the pod sends the file:
|
|
46
|
+
- JSON body: the handle's slot becomes the file's base64 (`{ image: args.photo }`), at most 20 MB of files per call.
|
|
47
|
+
- `opts.multipart: true`: a `multipart/form-data` form. A handle, or a list of handles, under a key becomes file parts of that field. Every other value is a text field: `callProvider("unipile_linkedin", "POST", "/api/v1/posts", { account_id, text, attachments: args.attachments }, { multipart: true })`.
|
|
48
|
+
- A handle works only in the run that received it, and only toward the skill's own required tools. `host.fetch` never sends it.
|
|
49
|
+
|
|
40
50
|
### `hubProtocol` (reads, as the user)
|
|
41
51
|
|
|
42
52
|
- `hubProtocol.getEntities({ profileSlug, limit })`: entities of one kind.
|
|
@@ -59,6 +69,10 @@ The governed write-back. Returns `{ status, proposalId, proposedEntityId, messag
|
|
|
59
69
|
2. It can still be off: when the person who approved may not turn verbs on (the approval result says so in `refusals`), or after its code changed (an edit turns it off until approved again). `synap_list_capabilities` then shows it as `blocked: "not_enabled"` with an `enable.url`: hand that link to the user instead of running it.
|
|
60
70
|
3. `console.log` goes to the pod log, not to your result: return what you need to see.
|
|
61
71
|
|
|
72
|
+
## Fixing a code skill
|
|
73
|
+
|
|
74
|
+
Change it in place with `synap_update_skill` (`id` or `slug`): it takes `code` (the whole new source), `parameters`, `timeoutSeconds` and `requiredTools` (the list replaces the declared set), as well as `body`, `description` and `name`. Never call `synap_create_skill` again under the same name: it is refused with the existing skill's id, because two skills with one name make a run by name ambiguous. A change to what the skill runs (code, parameters, timeout, a tool added) turns it off until the person approves it again: read `synap_list_capabilities` before running it.
|
|
75
|
+
|
|
62
76
|
## Box scripts (packages, files, Python or Node)
|
|
63
77
|
|
|
64
78
|
When the work needs packages, files or another language (chart a CSV with pandas, convert a file, scrape with a headless browser), write a BOX script instead: `synap_create_skill` with `executionMode: "box"`, the script in `code` (a whole program, not a function body) and `box: { language: "python" | "node", packages: [{ name, version }], hosts: ["api.example.com"], limits? }`.
|
package/skills/synap/concepts.md
CHANGED
|
@@ -2,32 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
The ONE glossary; other skills point here. Word = what the user sees; internal = tools and tables.
|
|
4
4
|
|
|
5
|
-
| Word | Internal | Answers
|
|
6
|
-
| ------------------- | ----------------------- |
|
|
7
|
-
| **Space** | workspace | which domain: kinds + tools?
|
|
8
|
-
| **Project** | project | what am I committed to, with whom?
|
|
9
|
-
| **Goal** | project_tracks | what goal am I pursuing?
|
|
10
|
-
| **Step** | stage | where does this work stand?
|
|
11
|
-
| **Work** | focus_session | what am I doing this sitting?
|
|
12
|
-
| **Template** | playbook | how do I reuse it?
|
|
13
|
-
| **Pack** | suite | which templates come together?
|
|
14
|
-
| **Rule** |
|
|
15
|
-
| **
|
|
16
|
-
| **
|
|
17
|
-
| **
|
|
18
|
-
| **
|
|
19
|
-
| **
|
|
20
|
-
| **
|
|
21
|
-
| **
|
|
22
|
-
| **
|
|
23
|
-
| **
|
|
24
|
-
| **
|
|
25
|
-
| **
|
|
26
|
-
| **
|
|
27
|
-
| **
|
|
28
|
-
| **
|
|
29
|
-
| **
|
|
30
|
-
| **
|
|
5
|
+
| Word | Internal | Answers | Test · e.g. · not |
|
|
6
|
+
| ------------------- | ----------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Space** | workspace | which domain: kinds + tools? | owns kinds, never done · CRM · not a project or method; findable, not emphasised |
|
|
8
|
+
| **Project** | project | what am I committed to, with whom? | ends with the commitment; spans spaces · a launch · not a task, method, or the owner's company |
|
|
9
|
+
| **Goal** | project_tracks | what goal am I pursuing? | in ONE project; open while it matters, or its judge closes it with a verdict; criteria say when it is done; work = sessions · grow the newsletter · tools say "track" |
|
|
10
|
+
| **Step** | stage | where does this work stand? | = the subject's status: move the thing, the step follows · legacy: steps of a goal started from a method |
|
|
11
|
+
| **Work** | focus_session | what am I doing this sitting? | one aim · no noun: "Start work" |
|
|
12
|
+
| **Template** | playbook | how do I reuse it? | kind DERIVED, never declared: scope session = work template (a method a session or worker follows), project = goal template (legacy); also space and automation templates |
|
|
13
|
+
| **Pack** | suite | which templates come together? | a bundle; depends on space templates, never creates a space |
|
|
14
|
+
| **Rule** | skill rule | what do my agents always follow? | a standing instruction written for agents · "always cite sources" · not an Automation, not Approvals |
|
|
15
|
+
| **Automation** | automation | what runs by itself, when? | standing · "every Monday…" · not a Rule, not Approvals |
|
|
16
|
+
| **Approvals** | governance rules | which AI writes wait for me? | decides review vs auto, does no work |
|
|
17
|
+
| **Tools** | capability, skill, tool | what can it act with? | one word; the detail shows the kind |
|
|
18
|
+
| **Card** | cell | what block did I make? | the made UI block · "a deals summary" · never Cell, Widget or Interface |
|
|
19
|
+
| **Display** | renderer | how does this kind look? | a card bound to a kind's slot · "Change display" · Renderer stays an engine word |
|
|
20
|
+
| **View** | view | how do I look at the data? | a saved arrangement of things · a table, a board · not a Card |
|
|
21
|
+
| **App** | built-in surface | what do I open in Synap? | CRM, Calendar, a space's own front end · never a space, never outside software |
|
|
22
|
+
| **Connected app** | application | which outside software holds a grant? | reaches the pod with a grant · not an App |
|
|
23
|
+
| **Account** | provider connection | which of my accounts is linked? | a person's link to an outside service · never Connection, Connector or Integration |
|
|
24
|
+
| **Kind** | profile | what shape does a thing have? | its fields and status list · never Data type, Schema or Profile |
|
|
25
|
+
| **Make** | destination | where do I make things? | a view, a card, a space, an automation · pairs with Work |
|
|
26
|
+
| **Get more** | destination | where do I add more? | the store · never Marketplace or Get more tools |
|
|
27
|
+
| **To review** | proposal | what awaits my approval? | `proposed` is success |
|
|
28
|
+
| **Role** | role profile + facet | which hat does it wear? | one role per name, pod-wide; spaces add properties by overlay; its entities show in all · client · never a twin |
|
|
29
|
+
| **Thing** | entity | what is being worked on? | one kind, maybe roles · a post, a lead · never a twin for a hat |
|
|
30
|
+
| **Status** | lifecycle | where does it stand? | ONE list per kind or role, declared on its profile; category open·active·paused·done·lost · moved only through the door (`expectedStatus`) |
|
|
31
|
+
| **Pipeline** | pipeline view | what is in each status? | computed from a lifecycle, never created · not an object |
|
|
32
|
+
| **Worker** | playbook activator | what starts work by itself? | a method + trigger (enters status · schedule · count · manual) + size (per thing · per batch); a goal or project turns it on |
|
|
33
|
+
| **Inbox** | needs-you signals | what needs me? | one list: decisions, questions, routine changes, broken · not Work |
|
|
34
|
+
| **Questions** | owed slot ask | what did an agent ask me? | an Inbox filter · answer it, the work resumes |
|
|
35
|
+
| **Routine changes** | reversible proposal | what can I approve in a batch? | an Inbox filter · only reversible changes batch; undo says what it cannot restore |
|
|
36
|
+
| **Broken** | failed or stuck work | what needs a fix? | an Inbox filter · a failed run, a stuck session |
|
|
37
|
+
| **Library** | data (things, files) | what did we bring in? | what you and your agents kept or made: things, files, imports · not a space |
|
|
38
|
+
| **Unfiled** | entity in no project | what is not filed yet? | things outside every project · file them into one |
|
|
39
|
+
| **Agents** | agent users + keys | who acts for me? | Claude Code, Codex, any MCP client; each has its own page · not a Tool |
|
|
40
|
+
| **Getting started** | first-run Home card | what do I try first? | goes away once done |
|
|
31
41
|
|
|
32
42
|
Doors: `start_track`, `start_session`, `create_rule`, `attach_facet`, `update_entity` + `expectedStatus` (a status). How they fit (sizes, workers, tenses): `work-model`.
|
|
33
43
|
|