portable-agent-layer 0.35.0 → 0.37.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 +2 -1
- package/assets/skills/analyze-pdf/tools/pdf-download.ts +1 -1
- package/assets/skills/analyze-youtube/tools/youtube-analyze.ts +1 -1
- package/assets/skills/consulting-report/tools/dev.ts +2 -2
- package/assets/skills/consulting-report/tools/generate-pdf.ts +9 -9
- package/assets/skills/consulting-report/tools/scaffold.ts +2 -2
- package/assets/skills/create-pdf/tools/md-to-html-pdf.ts +2 -2
- package/assets/skills/opinion/tools/opinion.ts +3 -2
- package/assets/skills/presentation/SKILL.md +1 -1
- package/assets/skills/presentation/tools/doctor.ts +2 -5
- package/assets/skills/presentation/tools/lib/inline.ts +6 -11
- package/assets/skills/presentation/tools/lib/lint-helpers.ts +2 -2
- package/assets/skills/presentation/tools/lib/lint-rules.ts +5 -2
- package/assets/skills/presentation/tools/setup-template.ts +10 -7
- package/assets/skills/projects/SKILL.md +44 -21
- package/assets/skills/research/tools/gemini-search.ts +2 -2
- package/assets/skills/research/tools/grok-search.ts +2 -2
- package/assets/skills/research/tools/perplexity-search.ts +2 -2
- package/assets/skills/telos/SKILL.md +7 -52
- package/assets/skills/telos/tools/update-telos.ts +0 -1
- package/assets/templates/PAL/ALGORITHM.md +54 -5
- package/assets/templates/PAL/PROJECT_LIFECYCLE.md +48 -0
- package/assets/templates/PAL/README.md +1 -1
- package/assets/templates/PAL/STEERING_RULES.md +4 -0
- package/assets/templates/PAL/SYSTEM_ARCHITECTURE.md +32 -17
- package/assets/templates/PAL/WORK_TRACKING.md +1 -1
- package/assets/templates/hooks.codex.json +44 -0
- package/assets/templates/hooks.cursor.json +11 -5
- package/assets/templates/pal-settings.json +1 -3
- package/assets/templates/settings.claude.json +2 -1
- package/package.json +2 -1
- package/src/cli/index.ts +112 -14
- package/src/cli/migrate.ts +299 -0
- package/src/cli/setup-identity.ts +3 -3
- package/src/cli/setup-telos.ts +12 -80
- package/src/hooks/CompactRecover.ts +11 -5
- package/src/hooks/LoadContext.ts +35 -11
- package/src/hooks/PreCompactPersist.ts +26 -34
- package/src/hooks/SecurityValidator.ts +43 -21
- package/src/hooks/StopOrchestrator.ts +4 -1
- package/src/hooks/UserPromptOrchestrator.ts +4 -2
- package/src/hooks/handlers/auto-graduate.ts +2 -2
- package/src/hooks/handlers/backup.ts +3 -3
- package/src/hooks/handlers/context-digests.ts +74 -0
- package/src/hooks/handlers/failure.ts +5 -3
- package/src/hooks/handlers/inject-retrieval.ts +29 -6
- package/src/hooks/handlers/persist-last-exchange.ts +76 -0
- package/src/hooks/handlers/rating.ts +2 -1
- package/src/hooks/handlers/readme-sync.ts +3 -2
- package/src/hooks/handlers/session-intelligence.ts +17 -93
- package/src/hooks/handlers/session-name.ts +2 -2
- package/src/hooks/handlers/synthesis.ts +5 -2
- package/src/hooks/handlers/update-counts.ts +3 -2
- package/src/hooks/lib/agent.ts +20 -18
- package/src/hooks/lib/claude-md.ts +69 -14
- package/src/hooks/lib/context.ts +92 -246
- package/src/hooks/lib/entities.ts +7 -7
- package/src/hooks/lib/frontmatter.ts +4 -4
- package/src/hooks/lib/graduation.ts +7 -6
- package/src/hooks/lib/inference.ts +6 -2
- package/src/hooks/lib/learning-category.ts +1 -1
- package/src/hooks/lib/learning-store.ts +6 -1
- package/src/hooks/lib/notify.ts +2 -2
- package/src/hooks/lib/opinions.ts +3 -3
- package/src/hooks/lib/paths.ts +2 -0
- package/src/hooks/lib/projects.ts +142 -74
- package/src/hooks/lib/readme-sync.ts +1 -1
- package/src/hooks/lib/relationship.ts +4 -16
- package/src/hooks/lib/retrieval-index.ts +5 -3
- package/src/hooks/lib/retrieval.ts +11 -12
- package/src/hooks/lib/security.ts +24 -18
- package/src/hooks/lib/semi-static.ts +188 -0
- package/src/hooks/lib/session-names.ts +1 -1
- package/src/hooks/lib/settings.ts +1 -1
- package/src/hooks/lib/setup.ts +2 -65
- package/src/hooks/lib/signals.ts +2 -2
- package/src/hooks/lib/stdin.ts +1 -1
- package/src/hooks/lib/stop.ts +16 -6
- package/src/hooks/lib/token-usage.ts +1 -2
- package/src/hooks/lib/transcript.ts +1 -1
- package/src/hooks/lib/wisdom.ts +5 -5
- package/src/hooks/lib/work-tracking.ts +8 -14
- package/src/targets/claude/uninstall.ts +1 -1
- package/src/targets/codex/install.ts +95 -0
- package/src/targets/codex/uninstall.ts +70 -0
- package/src/targets/copilot/install.ts +39 -8
- package/src/targets/copilot/uninstall.ts +58 -17
- package/src/targets/cursor/install.ts +8 -0
- package/src/targets/cursor/uninstall.ts +18 -1
- package/src/targets/lib.ts +166 -14
- package/src/targets/opencode/install.ts +29 -1
- package/src/targets/opencode/plugin.ts +23 -12
- package/src/targets/opencode/uninstall.ts +30 -3
- package/src/tools/agent/algorithm-reflect.ts +1 -1
- package/src/tools/agent/analyze.ts +18 -18
- package/src/tools/agent/handoff-note.ts +116 -0
- package/src/tools/agent/project.ts +375 -75
- package/src/tools/agent/relationship-note.ts +51 -0
- package/src/tools/agent/synthesize.ts +6 -42
- package/src/tools/agent/thread.ts +15 -14
- package/src/tools/agent/wisdom-frame.ts +9 -3
- package/src/tools/import.ts +1 -1
- package/src/tools/relationship-reflect.ts +15 -13
- package/src/tools/self-model.ts +23 -19
- package/src/tools/session-summary.ts +3 -3
- package/src/tools/token-cost.ts +15 -16
- package/assets/skills/telos/tools/update-projects.ts +0 -106
- package/assets/templates/telos/PROJECTS.md +0 -7
package/README.md
CHANGED
|
@@ -82,6 +82,7 @@ pal cli status # check your setup
|
|
|
82
82
|
| `pal cli import` | Import user state from a zip |
|
|
83
83
|
| `pal cli status` | Show current PAL configuration |
|
|
84
84
|
| `pal cli doctor` | Check prerequisites and system health |
|
|
85
|
+
| `pal cli migrate` | Run pending data migrations (non-destructive) |
|
|
85
86
|
| `pal cli usage` | Summarize token usage and estimated cost |
|
|
86
87
|
|
|
87
88
|
### Target flags
|
|
@@ -102,7 +103,7 @@ pal cli install # all available (default)
|
|
|
102
103
|
| Claude Code | Full | Yes | Yes | Yes | Yes |
|
|
103
104
|
| opencode | Full | Yes | Yes (plugin) | Yes | Yes |
|
|
104
105
|
| Cursor | Full | Yes | Yes | Yes (injected via hook) | Yes |
|
|
105
|
-
| GitHub Copilot | Full | Yes | Yes | Yes (via copilot
|
|
106
|
+
| GitHub Copilot | Full | Yes | Yes | Yes (via `~/.copilot/instructions/*.instructions.md`) | Yes |
|
|
106
107
|
| Codex | Partial | Yes | No | Yes | No |
|
|
107
108
|
|
|
108
109
|
---
|
|
@@ -19,7 +19,7 @@ async function exists(p: string): Promise<boolean> {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
async function dev(reportDir: string): Promise<number> {
|
|
23
23
|
const dir = resolve(reportDir);
|
|
24
24
|
const pkg = join(dir, "package.json");
|
|
25
25
|
if (!(await exists(pkg))) {
|
|
@@ -33,7 +33,7 @@ export async function dev(reportDir: string): Promise<number> {
|
|
|
33
33
|
return result.status ?? 1;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
async function run(argv: string[] = process.argv.slice(2)): Promise<void> {
|
|
37
37
|
if (argv.length === 0) {
|
|
38
38
|
console.error("usage: dev.ts <report-dir>");
|
|
39
39
|
process.exit(1);
|
|
@@ -43,10 +43,10 @@ async function exists(p: string): Promise<boolean> {
|
|
|
43
43
|
|
|
44
44
|
function escapeHtml(s: string): string {
|
|
45
45
|
return s
|
|
46
|
-
.
|
|
47
|
-
.
|
|
48
|
-
.
|
|
49
|
-
.
|
|
46
|
+
.replaceAll("&", "&")
|
|
47
|
+
.replaceAll("<", "<")
|
|
48
|
+
.replaceAll(">", ">")
|
|
49
|
+
.replaceAll('"', """);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function slugify(s: string): string {
|
|
@@ -56,7 +56,7 @@ function slugify(s: string): string {
|
|
|
56
56
|
.replace(/^-|-$/g, "");
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
async function loadMeta(reportDir: string): Promise<ReportMeta> {
|
|
60
60
|
const dataPath = join(reportDir, "lib", "report-data.ts");
|
|
61
61
|
if (!(await exists(dataPath))) {
|
|
62
62
|
throw new Error(`lib/report-data.ts not found at ${dataPath}`);
|
|
@@ -70,7 +70,7 @@ export async function loadMeta(reportDir: string): Promise<ReportMeta> {
|
|
|
70
70
|
return mod.reportData;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
function buildNext(reportDir: string): void {
|
|
74
74
|
const result = spawnSync("bun", ["run", "build"], {
|
|
75
75
|
cwd: reportDir,
|
|
76
76
|
stdio: "inherit",
|
|
@@ -121,7 +121,7 @@ function serveStatic(rootDir: string): Promise<{ server: Server; url: string }>
|
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
async function renderPdf(
|
|
125
125
|
htmlPath: string,
|
|
126
126
|
pdfPath: string,
|
|
127
127
|
meta: ReportMeta
|
|
@@ -186,7 +186,7 @@ interface GenerateOptions {
|
|
|
186
186
|
skipBuild?: boolean;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
async function generate(opts: GenerateOptions): Promise<{
|
|
190
190
|
htmlPath: string;
|
|
191
191
|
pdfPath: string;
|
|
192
192
|
}> {
|
|
@@ -227,7 +227,7 @@ function parseArgs(argv: string[]): GenerateOptions {
|
|
|
227
227
|
return opts;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
async function run(argv: string[] = process.argv.slice(2)): Promise<void> {
|
|
231
231
|
const opts = parseArgs(argv);
|
|
232
232
|
const { htmlPath, pdfPath } = await generate(opts);
|
|
233
233
|
const [htmlStat, pdfStat] = await Promise.all([stat(htmlPath), stat(pdfPath)]);
|
|
@@ -34,7 +34,7 @@ function templateDir(): string {
|
|
|
34
34
|
return resolve(here, "..", "template");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
async function scaffold(opts: ScaffoldOptions): Promise<void> {
|
|
38
38
|
const tpl = templateDir();
|
|
39
39
|
if (!(await exists(tpl))) {
|
|
40
40
|
throw new Error(`template not found at ${tpl}`);
|
|
@@ -91,7 +91,7 @@ function parseArgs(argv: string[]): ScaffoldOptions {
|
|
|
91
91
|
return opts;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
async function run(argv: string[] = process.argv.slice(2)): Promise<void> {
|
|
95
95
|
const opts = parseArgs(argv);
|
|
96
96
|
await scaffold(opts);
|
|
97
97
|
console.log(`Scaffolded: ${opts.targetDir}`);
|
|
@@ -30,8 +30,8 @@ for (let i = 1; i < args.length; i++) {
|
|
|
30
30
|
}
|
|
31
31
|
const stem = basename(input, extname(input));
|
|
32
32
|
const dir = dirname(input);
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
htmlOut ??= resolve(dir, `${stem}.html`);
|
|
34
|
+
pdfOut ??= resolve(dir, `${stem}.pdf`);
|
|
35
35
|
|
|
36
36
|
const md = await readFile(input, "utf8");
|
|
37
37
|
marked.setOptions({ gfm: true, breaks: false });
|
|
@@ -70,8 +70,9 @@ switch (command) {
|
|
|
70
70
|
console.log(` ${c.cyan(category)}`);
|
|
71
71
|
for (const op of ops.sort((a, b) => b.confidence - a.confidence)) {
|
|
72
72
|
const pct = `${Math.round(op.confidence * 100)}%`;
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
let color = c.yellow;
|
|
74
|
+
if (op.confidence >= 0.85) color = c.green;
|
|
75
|
+
else if (op.confidence <= 0.3) color = c.red;
|
|
75
76
|
console.log(` [${bar(op.confidence)}] ${color(pct)} ${op.statement}`);
|
|
76
77
|
}
|
|
77
78
|
console.log("");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: presentation
|
|
3
|
-
description: Build branded HTML presentations from markdown using Reveal.js. Multi-template registry per user (each template = brand color, logo, fonts, footer, aspect). Per-deck workflow: scaffold → edit one markdown file per slide in slides/ → build → present. Output: a `<deck-name>/` subdir with a self-contained HTML and a concatenated markdown sibling. 14 layouts including data-display patterns (big-stat, metric-grid). Use when creating slide decks, talks, workshop slides, lectures, or pitch decks.
|
|
3
|
+
description: "Build branded HTML presentations from markdown using Reveal.js. Multi-template registry per user (each template = brand color, logo, fonts, footer, aspect). Per-deck workflow: scaffold → edit one markdown file per slide in slides/ → build → present. Output: a `<deck-name>/` subdir with a self-contained HTML and a concatenated markdown sibling. 14 layouts including data-display patterns (big-stat, metric-grid). Use when creating slide decks, talks, workshop slides, lectures, or pitch decks."
|
|
4
4
|
argument-hint: <deck-dir> to build, OR `setup-template` to add a brand template, OR `new <deck-dir> --template <name>` to scaffold a deck, OR `list-templates`
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -23,10 +23,8 @@ import {
|
|
|
23
23
|
import { RULES } from "./lib/lint-rules";
|
|
24
24
|
import type { DeckContext, Finding, SlideContext, SlideReport } from "./lib/lint-types";
|
|
25
25
|
|
|
26
|
-
// Re-export for backward compatibility with external callers (tests, etc.)
|
|
27
|
-
// that imported these directly from doctor.ts.
|
|
28
26
|
export { extractLayout } from "./lib/lint-helpers";
|
|
29
|
-
export type {
|
|
27
|
+
export type { Finding } from "./lib/lint-types";
|
|
30
28
|
|
|
31
29
|
async function loadSlides(deckDir: string): Promise<{ name: string; body: string }[]> {
|
|
32
30
|
const slidesDir = join(deckDir, "slides");
|
|
@@ -64,7 +62,7 @@ function buildSlideContext(
|
|
|
64
62
|
};
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
async function lintDeck(deckDir: string): Promise<{
|
|
68
66
|
slides: SlideContext[];
|
|
69
67
|
reports: SlideReport[];
|
|
70
68
|
deckFindings: Finding[];
|
|
@@ -95,7 +93,6 @@ export async function lintDeck(deckDir: string): Promise<{
|
|
|
95
93
|
return { slides, reports, deckFindings };
|
|
96
94
|
}
|
|
97
95
|
|
|
98
|
-
// Public: kept for any external caller that imported `lintSlide` directly.
|
|
99
96
|
export async function lintSlide(
|
|
100
97
|
slide: { name: string; body: string },
|
|
101
98
|
deckDir: string
|
|
@@ -7,21 +7,16 @@ export async function readText(path: string): Promise<string> {
|
|
|
7
7
|
|
|
8
8
|
export async function dataUri(path: string): Promise<string> {
|
|
9
9
|
const ext = extname(path).toLowerCase();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
: ext === ".jpg" || ext === ".jpeg"
|
|
16
|
-
? "image/jpeg"
|
|
17
|
-
: ext === ".webp"
|
|
18
|
-
? "image/webp"
|
|
19
|
-
: "application/octet-stream";
|
|
10
|
+
let mime = "application/octet-stream";
|
|
11
|
+
if (ext === ".svg") mime = "image/svg+xml";
|
|
12
|
+
else if (ext === ".png") mime = "image/png";
|
|
13
|
+
else if (ext === ".jpg" || ext === ".jpeg") mime = "image/jpeg";
|
|
14
|
+
else if (ext === ".webp") mime = "image/webp";
|
|
20
15
|
|
|
21
16
|
if (ext === ".svg") {
|
|
22
17
|
// Inline SVGs as URL-encoded text — smaller than base64 and renders crisply at any size.
|
|
23
18
|
const svg = await readFile(path, "utf8");
|
|
24
|
-
const enc = encodeURIComponent(svg).
|
|
19
|
+
const enc = encodeURIComponent(svg).replaceAll("'", "%27").replaceAll('"', "%22");
|
|
25
20
|
return `url("data:${mime};utf8,${enc}")`;
|
|
26
21
|
}
|
|
27
22
|
|
|
@@ -39,7 +39,7 @@ export function extractNotes(body: string): string {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function countAtxHeading(body: string, level: 1 | 2): string[] {
|
|
42
|
-
const re = new RegExp(`^#{${level}}
|
|
42
|
+
const re = new RegExp(String.raw`^#{${level}}\s+(.+?)\s*$`, "gm");
|
|
43
43
|
return Array.from(body.matchAll(re), (m) => m[1]);
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -71,7 +71,7 @@ export type ListItem = {
|
|
|
71
71
|
export function listItems(body: string): ListItem[] {
|
|
72
72
|
const out: ListItem[] = [];
|
|
73
73
|
for (const line of body.split("\n")) {
|
|
74
|
-
const m =
|
|
74
|
+
const m = new RegExp(/^(\s*)(?:[-*]\s+|\d+\.\s+)(.*)$/).exec(line);
|
|
75
75
|
if (!m) continue;
|
|
76
76
|
out.push({ indent: m[1].length, content: m[2], raw: line });
|
|
77
77
|
}
|
|
@@ -125,7 +125,7 @@ export const RULES: Rule[] = [
|
|
|
125
125
|
// pretending to be a bullet. Convert to a sub-bullet instead.
|
|
126
126
|
const findings: Finding[] = [];
|
|
127
127
|
for (const line of ctx.bodyNoNotes.split("\n")) {
|
|
128
|
-
const m =
|
|
128
|
+
const m = new RegExp(/^(\s*)(?:[-*]\s+|\d+\.\s+)(.*)$/).exec(line);
|
|
129
129
|
if (!m) continue;
|
|
130
130
|
const stripped = stripCodeAndLinks(m[2]);
|
|
131
131
|
if (/\s—\s/.test(stripped)) {
|
|
@@ -338,7 +338,10 @@ export const RULES: Rule[] = [
|
|
|
338
338
|
"Anticipated questions",
|
|
339
339
|
];
|
|
340
340
|
for (const beat of required) {
|
|
341
|
-
const re = new RegExp(
|
|
341
|
+
const re = new RegExp(
|
|
342
|
+
String.raw`^[-*]\s+${beat.replace(/\s+/g, "\\s+")}\b`,
|
|
343
|
+
"im"
|
|
344
|
+
);
|
|
342
345
|
if (!re.test(notes)) {
|
|
343
346
|
findings.push({
|
|
344
347
|
rule: "exercise-note-beats",
|
|
@@ -167,11 +167,14 @@ async function main() {
|
|
|
167
167
|
|
|
168
168
|
// 2. Path
|
|
169
169
|
const defaultPath = join(TEMPLATES_ROOT, name);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
let tplPath: string;
|
|
171
|
+
if (args.path) {
|
|
172
|
+
tplPath = resolve(args.path);
|
|
173
|
+
} else if (rl) {
|
|
174
|
+
tplPath = resolve(await ask(rl, "Storage path:", defaultPath));
|
|
175
|
+
} else {
|
|
176
|
+
tplPath = defaultPath;
|
|
177
|
+
}
|
|
175
178
|
|
|
176
179
|
// 3. Logo
|
|
177
180
|
let logo = args.logo;
|
|
@@ -231,7 +234,7 @@ async function main() {
|
|
|
231
234
|
["cover-only", "footer", "both", "none"].includes(a) ? a : "footer"
|
|
232
235
|
) as LogoPlacement;
|
|
233
236
|
}
|
|
234
|
-
|
|
237
|
+
logoPlacement ??= "footer";
|
|
235
238
|
|
|
236
239
|
// 8. Fonts
|
|
237
240
|
const fonts =
|
|
@@ -244,7 +247,7 @@ async function main() {
|
|
|
244
247
|
const a = await ask(rl, "Aspect ratio [16:9 / 4:3 / 16:10]:", "16:9");
|
|
245
248
|
aspect = (["16:9", "4:3", "16:10"].includes(a) ? a : "16:9") as Aspect;
|
|
246
249
|
}
|
|
247
|
-
|
|
250
|
+
aspect ??= "16:9";
|
|
248
251
|
|
|
249
252
|
// 10. Showcase deck?
|
|
250
253
|
let showcase = args.showcase;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: projects
|
|
3
3
|
description: Project context management. PROACTIVE — use when the user references a project (by name or as "this repo", "current work"), asks to add/update/complete a project, says "store under <project>", "track this", "what am I working on", "my projects", "my priorities".
|
|
4
|
-
argument-hint: [list | create | resume | add-
|
|
4
|
+
argument-hint: [list | create | resume | add-next | add-blocker | add-decision | add-handoff | update-section | criteria | isa-init | complete | archive | pause]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Manage the user's project registry. Each project
|
|
7
|
+
Manage the user's project registry. Each project lives at `~/.pal/memory/projects/{slug}/ISA.md`. Frontmatter holds operational state (next steps, blockers, handoff); the body holds ISA spec sections (Problem, Goal, Criteria, Context, Decisions, etc.). The Stop hook auto-touches `updated` whenever the cwd resolves into a registered project — just *being* in the project keeps it warm.
|
|
8
8
|
|
|
9
9
|
## CLI
|
|
10
10
|
|
|
@@ -20,16 +20,33 @@ Output is JSON.
|
|
|
20
20
|
|---------|---------|
|
|
21
21
|
| `list` | All registered projects with status, path, updated, stale flag, and counts |
|
|
22
22
|
| `create [name] [--path PATH] [--objectives "a;b;c"]` | Register a project. Defaults: name=basename(cwd), path=cwd. Slug must be `[a-z0-9_-]+` |
|
|
23
|
-
| `resume <name>` | Print the full project
|
|
24
|
-
| `add-
|
|
25
|
-
| `add-
|
|
26
|
-
| `add-
|
|
27
|
-
| `add-
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
23
|
+
| `resume <name>` | Print the full project ISA — all frontmatter and body sections |
|
|
24
|
+
| `add-next <name> "text"` | Append a next step (array, instantly appendable) |
|
|
25
|
+
| `add-blocker <name> "text"` | Append a blocker (array, instantly appendable) |
|
|
26
|
+
| `add-decision <name> "decision" "rationale"` | Log a timestamped decision entry to the Decisions section |
|
|
27
|
+
| `add-handoff <name> "text"` | Overwrite the handoff field (single-value, replaces) |
|
|
28
|
+
| `rm-next \| rm-blocker <name> <index>` | Remove a next/blocker entry by zero-based index |
|
|
29
|
+
| `update-section <name> <section> "content"` | Set an ISA body section (problem, goal, criteria, vision, constraints, out_of_scope, context, decisions, changelog) |
|
|
30
|
+
| `criteria <name>` | Print the Criteria section (verifiable success conditions) |
|
|
31
|
+
| `isa-init <name>` | Mark a project as ISA-initialized |
|
|
31
32
|
| `complete <name>` / `archive <name>` / `pause <name>` / `unpause <name>` | Status transitions |
|
|
32
|
-
| `rm <name>` | Delete the project
|
|
33
|
+
| `rm <name>` | Delete the project directory entirely |
|
|
34
|
+
|
|
35
|
+
## ISA Sections
|
|
36
|
+
|
|
37
|
+
The body of each ISA.md holds spec sections. Use `update-section` to set them:
|
|
38
|
+
|
|
39
|
+
| Section | Key | What goes here |
|
|
40
|
+
|---------|-----|---------------|
|
|
41
|
+
| Problem | `problem` | Why this project exists; the pain or gap being addressed |
|
|
42
|
+
| Goal | `goal` | What success looks like (may be bullet list) |
|
|
43
|
+
| Criteria | `criteria` | Verifiable done conditions — testable ISCs (Ideal State Criteria) |
|
|
44
|
+
| Vision | `vision` | Long-horizon aspiration beyond the immediate goal |
|
|
45
|
+
| Constraints | `constraints` | Non-negotiable limits (budget, time, tech, compatibility) |
|
|
46
|
+
| Out of Scope | `out_of_scope` | What this project explicitly does NOT cover |
|
|
47
|
+
| Context | `context` | Stable facts / references (e.g. "reference impl lives at ~/pai") |
|
|
48
|
+
| Decisions | `decisions` | Auto-managed by `add-decision`; dated bullet list |
|
|
49
|
+
| Changelog | `changelog` | Summary of completed milestones |
|
|
33
50
|
|
|
34
51
|
## Routing
|
|
35
52
|
|
|
@@ -38,9 +55,11 @@ Output is JSON.
|
|
|
38
55
|
| "what am I working on", "my projects", "priorities" | `list` — summarize active and recently-touched projects |
|
|
39
56
|
| "tell me about <project>" | `resume <name>` — present current state, highlight blockers and next steps |
|
|
40
57
|
| "register this" / "track this" / cwd is unregistered work | `create` (default the name from cwd basename, confirm before writing) |
|
|
41
|
-
| "store under <project>: X" / "note on <project>: X" | Pick the field — durable reference → `
|
|
58
|
+
| "store under <project>: X" / "note on <project>: X" | Pick the field — durable reference → `update-section <slug> context "..."`, work item → `add-next`, obstacle → `add-blocker`. If unclear, ask. |
|
|
42
59
|
| "we decided X because Y" | `add-decision <name> "X" "Y"` |
|
|
43
60
|
| "handoff for <project>" / "next session pick up at X" | `add-handoff <name> "<text>"` |
|
|
61
|
+
| "set the goal for <project>" / "describe the problem" | `update-section <name> goal "..."` or `update-section <name> problem "..."` |
|
|
62
|
+
| "what are the criteria for <project>" / "what counts as done" | `criteria <name>` |
|
|
44
63
|
| "mark X complete" / "X is done" | `complete <name>` |
|
|
45
64
|
| "park <project>" / "pause <project>" | `pause <name>` |
|
|
46
65
|
| "archive <project>" | `archive <name>` |
|
|
@@ -53,7 +72,7 @@ When SessionStart context flags the current cwd as unregistered (e.g. `💡 cwd
|
|
|
53
72
|
|
|
54
73
|
- **Default name** = the FULL last path segment of cwd, lowercased. For `/repos/portable-agent-layer` → `portable-agent-layer`. Never split on `-`.
|
|
55
74
|
- **Confirm before creating.** Never auto-create without explicit user approval ("yes", "do it", "register").
|
|
56
|
-
- **Capture
|
|
75
|
+
- **Capture context in conversation.** If the user accepts but doesn't volunteer a goal, ask one short question, or infer from the last few messages and confirm.
|
|
57
76
|
|
|
58
77
|
### When NOT to suggest registration
|
|
59
78
|
|
|
@@ -64,7 +83,7 @@ When SessionStart context flags the current cwd as unregistered (e.g. `💡 cwd
|
|
|
64
83
|
|
|
65
84
|
## Append-as-you-go
|
|
66
85
|
|
|
67
|
-
When the user describes
|
|
86
|
+
When the user describes next steps, blockers, or decisions during normal work, invoke the relevant subcommand to keep state current — that's the dynamism this system is built for. Don't invoke for fleeting comments, hypotheticals, or things the user is just thinking through. Wait for a clear declarative ("let's add X", "Z is blocking us"), not a question or musing.
|
|
68
87
|
|
|
69
88
|
## Examples
|
|
70
89
|
|
|
@@ -72,8 +91,8 @@ When the user describes plans, blockers, or decisions during normal work, invoke
|
|
|
72
91
|
```
|
|
73
92
|
User: "store under <project> that a reference implementation exists in this repo"
|
|
74
93
|
→ Identify the project from `list` (or by name)
|
|
75
|
-
→ Durable reference, not a task →
|
|
76
|
-
→ bun ~/.pal/tools/project.ts
|
|
94
|
+
→ Durable reference, not a task → update-section
|
|
95
|
+
→ bun ~/.pal/tools/project.ts update-section <slug> context "Reference implementation lives in this repo"
|
|
77
96
|
```
|
|
78
97
|
|
|
79
98
|
**Registering the current repo**
|
|
@@ -89,6 +108,12 @@ User: "we decided <decision> because <reason>"
|
|
|
89
108
|
→ bun ~/.pal/tools/project.ts add-decision <slug> "<decision>" "<reason>"
|
|
90
109
|
```
|
|
91
110
|
|
|
111
|
+
**Setting the goal and criteria**
|
|
112
|
+
```
|
|
113
|
+
User: "set the goal for pal to 'ship ISA support with full test coverage'"
|
|
114
|
+
→ bun ~/.pal/tools/project.ts update-section pal goal "ship ISA support with full test coverage"
|
|
115
|
+
```
|
|
116
|
+
|
|
92
117
|
**Completing a project**
|
|
93
118
|
```
|
|
94
119
|
User: "mark <project> as complete"
|
|
@@ -98,11 +123,9 @@ User: "mark <project> as complete"
|
|
|
98
123
|
|
|
99
124
|
## Anti-patterns
|
|
100
125
|
|
|
101
|
-
- **Don't dump the full
|
|
102
|
-
- **Don't write without confirming the field choice on ambiguous "store" requests.** A
|
|
103
|
-
- **Don't edit
|
|
104
|
-
- **Don't re-introduce `~/.pal/telos/PROJECTS.md`.** That file and its `update-projects.ts` tool are deprecated. The legacy `telos` skill carries a deprecation notice for this reason.
|
|
105
|
-
- **Don't confuse `add-fact` with the `telos` skill's `LEARNED.md` or `IDEAS.md`.** Project facts are scoped to one project; TELOS lessons are cross-cutting.
|
|
126
|
+
- **Don't dump the full ISA.md.** Summarize. The user can ask for the raw payload.
|
|
127
|
+
- **Don't write without confirming the field choice on ambiguous "store" requests.** A context fact sticks forever; a next step implies follow-up — these are different commitments.
|
|
128
|
+
- **Don't edit ISA.md files directly.** Always use the CLI — it timestamps `updated` and keeps the schema valid.
|
|
106
129
|
|
|
107
130
|
## Rules
|
|
108
131
|
|
|
@@ -70,7 +70,7 @@ Distinguish between peer-reviewed findings and preprints/working papers.
|
|
|
70
70
|
Note methodology limitations and sample sizes when relevant.
|
|
71
71
|
Be thorough but concise.`;
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
async function geminiSearch(query: string, maxTokens: number): Promise<void> {
|
|
74
74
|
const apiKey = loadApiKey();
|
|
75
75
|
|
|
76
76
|
const body = {
|
|
@@ -183,4 +183,4 @@ Examples:
|
|
|
183
183
|
await geminiSearch(query, maxTokens);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
if (import.meta.main) run();
|
|
186
|
+
if (import.meta.main) void run();
|
|
@@ -70,7 +70,7 @@ function sourcesToTools(sources: SourceType[]): ToolType[] {
|
|
|
70
70
|
return sources.map((s) => map[s]);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
async function grokSearch(
|
|
74
74
|
query: string,
|
|
75
75
|
sources: SourceType[],
|
|
76
76
|
maxTokens: number
|
|
@@ -189,4 +189,4 @@ Examples:
|
|
|
189
189
|
await grokSearch(query, sources, maxTokens);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
if (import.meta.main) run();
|
|
192
|
+
if (import.meta.main) void run();
|
|
@@ -58,7 +58,7 @@ Distinguish between confirmed facts, single-source claims, and unverified allega
|
|
|
58
58
|
Flag contradictions between sources.
|
|
59
59
|
Be thorough but concise.`;
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
async function perplexitySearch(query: string, maxTokens: number): Promise<void> {
|
|
62
62
|
const apiKey = loadApiKey();
|
|
63
63
|
|
|
64
64
|
const body = {
|
|
@@ -147,4 +147,4 @@ Examples:
|
|
|
147
147
|
await perplexitySearch(query, maxTokens);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
if (import.meta.main) run();
|
|
150
|
+
if (import.meta.main) void run();
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: telos
|
|
3
|
-
description: Personal context management. Use when discussing goals, beliefs, challenges, identity, updating telos, life context, changing a goal,
|
|
3
|
+
description: Personal context management. Use when discussing goals, beliefs, challenges, identity, updating telos, life context, changing a goal, what do I believe, current obstacles, mission, or strategies.
|
|
4
4
|
argument-hint: [area to view or update]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
> ⚠️ **DEPRECATION NOTICE — Project management has moved.**
|
|
8
|
-
> Project tracking is now handled by the `projects` skill, backed by `~/.pal/tools/project.ts` and per-project state in `~/.pal/memory/state/progress/`. **Do not use this skill for projects.** The `PROJECTS.md` references and `update-projects.ts` tool below are legacy and slated for removal — they remain only because the initial setup wizard (`src/cli/setup-telos.ts`) still depends on them. For anything project-related, invoke the `projects` skill.
|
|
9
|
-
|
|
10
7
|
Manage the user's TELOS files — the persistent personal context that drives PAL.
|
|
11
8
|
|
|
12
9
|
## TELOS Files
|
|
@@ -16,7 +13,6 @@ All files live in `~/.pal/telos/`:
|
|
|
16
13
|
| File | Contains |
|
|
17
14
|
|------|----------|
|
|
18
15
|
| `GOALS.md` | Short/medium/long-term goals |
|
|
19
|
-
| `PROJECTS.md` | Active projects, status, priority |
|
|
20
16
|
| `BELIEFS.md` | Core principles and values |
|
|
21
17
|
| `CHALLENGES.md` | Current obstacles |
|
|
22
18
|
| `MISSION.md` | Purpose and direction |
|
|
@@ -32,33 +28,18 @@ Read the file directly from `~/.pal/telos/` when the user asks about any area. S
|
|
|
32
28
|
|
|
33
29
|
## Updating
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
For all files except PROJECTS.md — appends content, creates backup, logs the change:
|
|
31
|
+
Appends content, creates backup, logs the change:
|
|
38
32
|
|
|
39
33
|
```bash
|
|
40
34
|
bun ~/.pal/skills/telos/tools/update-telos.ts <FILE> "<content>" "<description>"
|
|
41
35
|
```
|
|
42
36
|
|
|
43
|
-
### Projects (upsert by ID)
|
|
44
|
-
|
|
45
|
-
For PROJECTS.md — upserts a row by the ID column. Replaces if the ID exists, appends if new:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
bun ~/.pal/skills/telos/tools/update-projects.ts <id> "<row>" "<description>"
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
The ID is the first column of the table. Use short, lowercase, kebab-case slugs (e.g., `my-project`, `side-gig`).
|
|
52
|
-
|
|
53
37
|
## Routing
|
|
54
38
|
|
|
55
39
|
| Intent | Action |
|
|
56
40
|
|--------|--------|
|
|
57
|
-
| "what am I working on", "my projects", "priorities" | Read `PROJECTS.md`, summarize active work |
|
|
58
41
|
| "my goals", "what are my goals" | Read `GOALS.md`, present current state |
|
|
59
|
-
| "update goals/
|
|
60
|
-
| "add a project", "new project" | Read `PROJECTS.md`, confirm with user, run update tool |
|
|
61
|
-
| "complete/remove a project" | Read `PROJECTS.md`, confirm with user, update status via tool |
|
|
42
|
+
| "update goals/beliefs/challenges" | Read the target file, discuss changes with user, then run update tool |
|
|
62
43
|
| "what do I believe", "my principles" | Read `BELIEFS.md` |
|
|
63
44
|
| "current obstacles", "challenges" | Read `CHALLENGES.md` |
|
|
64
45
|
| "I learned something", "lesson" | Discuss, then append to `LEARNED.md` via tool |
|
|
@@ -67,38 +48,12 @@ The ID is the first column of the table. Use short, lowercase, kebab-case slugs
|
|
|
67
48
|
|
|
68
49
|
## Examples
|
|
69
50
|
|
|
70
|
-
**
|
|
71
|
-
```
|
|
72
|
-
User: "what am I working on?"
|
|
73
|
-
→ Read PROJECTS.md
|
|
74
|
-
→ Summarize active work by priority — don't list every column
|
|
75
|
-
→ Highlight status changes, blockers, what needs attention
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
**Example 2: Adding a project**
|
|
79
|
-
```
|
|
80
|
-
User: "add my new side project"
|
|
81
|
-
→ Ask: "What's the project name, status, and priority?"
|
|
82
|
-
→ User provides details
|
|
83
|
-
→ Show the row you'll add, confirm
|
|
84
|
-
→ Run: bun ~/.pal/skills/telos/tools/update-projects.ts side-project "| side-project | Side Project | In progress | Medium | Description |" "Added Side Project"
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
**Example 3: Updating a project**
|
|
88
|
-
```
|
|
89
|
-
User: "mark X as complete"
|
|
90
|
-
→ Read PROJECTS.md, find the entry and its ID
|
|
91
|
-
→ Show updated row, confirm
|
|
92
|
-
→ Run: bun ~/.pal/skills/telos/tools/update-projects.ts some-id "| some-id | Project Name | Complete | High | ... |" "Marked project as complete"
|
|
93
|
-
→ The existing row is replaced, not duplicated
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**Example 4: Updating goals**
|
|
51
|
+
**Updating goals**
|
|
97
52
|
```
|
|
98
53
|
User: "I finished the migration, update my goals"
|
|
99
54
|
→ Read GOALS.md to see current state
|
|
100
55
|
→ Discuss what changed — what's done, what's next
|
|
101
|
-
→ Run tool with
|
|
56
|
+
→ Run tool with updated content
|
|
102
57
|
→ Remind: CLAUDE.md regenerates next session
|
|
103
58
|
```
|
|
104
59
|
|
|
@@ -106,8 +61,8 @@ User: "I finished the migration, update my goals"
|
|
|
106
61
|
|
|
107
62
|
- **Don't dump raw file contents.** Summarize what's relevant to the user's question. They can ask for the full file if needed.
|
|
108
63
|
- **Don't update without confirming.** Always show what you'll change and get a "yes" before running the tool.
|
|
109
|
-
- **Don't create new TELOS files.** Only the
|
|
110
|
-
- **Don't mix TELOS with identity.** AI/principal identity lives in `pal-settings.json`, not TELOS. TELOS is personal context — goals, beliefs,
|
|
64
|
+
- **Don't create new TELOS files.** Only the 9 listed files are valid. If something doesn't fit, suggest the closest match.
|
|
65
|
+
- **Don't mix TELOS with identity.** AI/principal identity lives in `pal-settings.json`, not TELOS. TELOS is personal context — goals, beliefs, challenges.
|
|
111
66
|
- **Don't reference stale data.** If TELOS was loaded earlier in the session via context routing, re-read the file before updating — it may have changed.
|
|
112
67
|
|
|
113
68
|
## Rules
|