portable-agent-layer 0.11.0 → 0.13.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.
@@ -0,0 +1,471 @@
1
+ # PAL System Architecture
2
+
3
+ <!--
4
+ SYSTEM ARCHITECTURE TEMPLATE
5
+ =============================
6
+ This file defines the GENERIC architecture patterns for any PAL installation.
7
+ These are the foundational patterns that apply to ALL PAL implementations.
8
+
9
+ WHAT GOES HERE:
10
+ - The Founding Principles (universal)
11
+ - Generic system patterns (skill structure, hook lifecycle, memory layout)
12
+ - Architecture diagrams showing how components interact
13
+ - Design philosophy and constraints
14
+
15
+ WHAT DOES NOT GO HERE:
16
+ - User-specific skill counts, configurations, or API keys
17
+ - Personal projects or deployment details
18
+ - Ephemeral state or session-specific information
19
+ -->
20
+
21
+ **The Founding Principles and Universal Architecture Patterns for the Portable Agent Layer**
22
+
23
+ ---
24
+
25
+ ## Core Philosophy
26
+
27
+ **PAL is scaffolding for AI, not a replacement for human intelligence.**
28
+
29
+ AI systems need structure to be reliable. Like physical scaffolding supports construction work, PAL provides the architectural framework that makes AI assistance dependable, maintainable, and effective — regardless of which AI agent runs underneath.
30
+
31
+ ---
32
+
33
+ ## The Founding Principles
34
+
35
+ ### 1. Portability First
36
+
37
+ **PAL exists so your AI context, memory, and workflows survive any single tool.**
38
+
39
+ AI agents come and go. Your accumulated knowledge, preferences, and workflows should not be locked into one vendor's tool. PAL abstracts the agent-specific layer so the same skills, hooks, memory, and configuration work across Claude Code, opencode, and future agents.
40
+
41
+ **What portability means in practice:**
42
+ - No agent-specific assumptions in core logic
43
+ - Agent-specific code isolated in `src/targets/`
44
+ - Skills, memory, and TELOS are agent-agnostic
45
+ - A single `pal cli install --<agent>` registers everything
46
+
47
+ ### 2. Cross-Platform by Default
48
+
49
+ **Every feature must work identically on macOS, Linux, and Windows.**
50
+
51
+ No platform-specific code without a portable fallback. Path resolution, shell commands, and file operations use cross-platform abstractions. Environment overrides (`PAL_HOME`, `PAL_PKG`, etc.) let users customize paths without touching code.
52
+
53
+ ### 3. The Continuously Upgrading Algorithm
54
+
55
+ **The Algorithm is the gravitational center — everything else exists to serve it.**
56
+
57
+ PAL is built around a universal pattern for accomplishing any task: **Current State → Ideal State** via verifiable criteria. This pattern applies at every scale.
58
+
59
+ Everything feeds back into improving The Algorithm:
60
+ - The **Memory System** captures signals from every interaction
61
+ - The **Hook System** detects sentiment, ratings, and behavioral patterns
62
+ - The **Learning System** organizes evidence by session
63
+ - The **Wisdom System** crystallizes recurring patterns into principles
64
+ - The **Relationship System** tracks how the user works and what they prefer
65
+
66
+ ### 4. Scaffolding > Model
67
+
68
+ **The system architecture matters more than the underlying AI model.**
69
+
70
+ A well-structured system with good scaffolding will outperform a more powerful model with poor structure. PAL's value comes from:
71
+ - Organized workflows that guide AI execution
72
+ - Routing systems that activate the right context
73
+ - Quality gates that verify outputs
74
+ - Memory systems that enable learning
75
+ - Feedback systems that provide awareness
76
+
77
+ ### 5. As Deterministic as Possible
78
+
79
+ **Favor predictable, repeatable outcomes over flexibility.**
80
+
81
+ - Same input → Same output
82
+ - Behavior defined by code and hooks, not prompt variations
83
+ - Version control tracks explicit changes
84
+ - Hooks run deterministic TypeScript, not prompt-driven logic
85
+
86
+ ### 6. Code Before Prompts
87
+
88
+ **Write code to solve problems, use prompts to orchestrate code.**
89
+
90
+ Prompts should never replicate functionality that code can provide:
91
+ - Hooks are TypeScript, not prompt instructions
92
+ - Tools are CLI programs, not natural language procedures
93
+ - Memory is structured JSON/JSONL, not freeform text
94
+ - Configuration is `pal-settings.json`, not prose in CLAUDE.md
95
+
96
+ ### 7. Clear Thinking + Prompting is King
97
+
98
+ **The quality of outcomes depends on the quality of thinking and prompts.**
99
+
100
+ Before any code, before any architecture — there must be clear thinking:
101
+ - Understand the problem deeply before solving it
102
+ - Define success criteria before building
103
+ - Challenge assumptions before accepting them
104
+ - Simplify before optimizing
105
+
106
+ ### 8. UNIX Philosophy
107
+
108
+ **Do one thing well. Compose tools through standard interfaces.**
109
+
110
+ - Each hook handler does one thing
111
+ - Each tool is a standalone CLI program
112
+ - Each skill is a self-contained capability
113
+ - Hooks compose via `Promise.allSettled` — independent, parallel, isolated failures
114
+ - Tools compose via `bun run tool:<name>` — standard I/O, exit codes
115
+
116
+ ### 9. CLI as Interface
117
+
118
+ **Every operation should be accessible via command line.**
119
+
120
+ - `pal cli <command>` for system management
121
+ - `bun run tool:<name>` for utilities
122
+ - Skills triggered via agent slash commands
123
+ - No hidden operations — everything is scriptable and testable
124
+
125
+ ### 10. Spec / Test First
126
+
127
+ **Define expected behavior before writing implementation.**
128
+
129
+ - Write tests before implementation
130
+ - Tests should fail initially
131
+ - Implement until tests pass
132
+ - Run `check-write`, `type-check`, and `test` after every edit
133
+
134
+ ### 11. Custom Skill Management
135
+
136
+ **Skills are the organizational unit for all domain expertise.**
137
+
138
+ Skills are active orchestrators, not passive documentation:
139
+ - **Self-activating:** Trigger automatically based on user request
140
+ - **Self-contained:** Package all context, workflows, and tools
141
+ - **Composable:** Can invoke other skills and agents
142
+ - **Evolvable:** Easy to add, modify, or deprecate
143
+
144
+ ### 12. Custom Memory System
145
+
146
+ **Automatic capture and preservation of valuable work.**
147
+
148
+ Every session, every insight, every decision — captured automatically:
149
+ - Relationship notes extracted via inference
150
+ - Learnings captured per session
151
+ - Ratings tracked (explicit and implicit)
152
+ - Wisdom crystallized from recurring patterns
153
+ - Failures logged for pattern avoidance
154
+
155
+ ### 13. Permission to Fail
156
+
157
+ **Explicit permission to say "I don't know" prevents hallucinations.**
158
+
159
+ The AI has explicit permission to say "I don't know" when:
160
+ - Information isn't available in context
161
+ - Multiple conflicting answers seem equally valid
162
+ - Verification isn't possible
163
+
164
+ Fabricating an answer is far worse than admitting uncertainty.
165
+
166
+ ---
167
+
168
+ ## Skill System Architecture
169
+
170
+ ### Canonical Skill Structure
171
+
172
+ ```
173
+ assets/skills/<name>/
174
+ ├── SKILL.md # Main skill file (REQUIRED)
175
+ └── tools/ # CLI tools for automation (optional)
176
+ └── tool-name.ts # TypeScript CLI tool
177
+ ```
178
+
179
+ ### SKILL.md Format
180
+
181
+ ```markdown
182
+ ---
183
+ name: skill-name
184
+ description: What it does. Use when [triggers]. Capabilities.
185
+ ---
186
+
187
+ # Skill Name
188
+
189
+ Brief description.
190
+
191
+ ## Workflow
192
+ [Steps, decision trees, or procedures]
193
+ ```
194
+
195
+ ### Key Rules
196
+
197
+ - **Description**: Used by the agent for skill matching — be specific about triggers
198
+ - **One SKILL.md per skill**: The single entry point
199
+ - **Tools are optional**: Only add when the skill needs CLI automation
200
+ - **Skills are agent-agnostic**: No agent-specific assumptions in SKILL.md
201
+
202
+ ---
203
+
204
+ ## Hook System Architecture
205
+
206
+ ### Lifecycle
207
+
208
+ ```
209
+ ┌─────────────────────┐
210
+ │ Session Start │──► LoadContext.ts
211
+ │ │ - Regenerate CLAUDE.md if stale
212
+ │ │ - Inject dynamic context (system-reminder)
213
+ └─────────────────────┘
214
+
215
+ ┌─────────────────────┐
216
+ │ User Prompt Submit │──► UserPromptOrchestrator.ts
217
+ │ │ - Rating capture (explicit/implicit)
218
+ │ │ - Session naming (first prompt)
219
+ └─────────────────────┘
220
+
221
+ ┌─────────────────────┐
222
+ │ Pre Tool Use │──► SecurityValidator.ts
223
+ │ │ - Bash command validation
224
+ │ │ - File path validation
225
+ │ │──► SkillGuard.ts
226
+ │ │ - Block false-positive skill matches
227
+ └─────────────────────┘
228
+
229
+ ┌─────────────────────┐
230
+ │ Stop │──► StopOrchestrator.ts
231
+ │ │ - Work session capture
232
+ │ │ - Relationship extraction (Haiku inference)
233
+ │ │ - Work learning capture
234
+ │ │ - Failure logging
235
+ │ │ - Reflect trigger check
236
+ │ │ - Auto-backup
237
+ │ │ - Count updates
238
+ │ │ - Tab reset
239
+ └─────────────────────┘
240
+ ```
241
+
242
+ ### Design Principles
243
+
244
+ - **Fail-open**: Hook errors never block the user's session
245
+ - **Parallel execution**: Stop handlers run via `Promise.allSettled` — one failure doesn't block others
246
+ - **Idempotent**: Handlers check for existing state before writing (e.g., session dedup)
247
+ - **Timeout-aware**: Inference calls have hard timeouts (8s default)
248
+ - **Subagent-aware**: `LoadContext.ts` skips heavy context loading for subagent sessions
249
+
250
+ ### Configuration
251
+
252
+ Hooks are registered in the agent's settings file during `pal cli install`:
253
+
254
+ ```json
255
+ {
256
+ "hooks": {
257
+ "SessionStart": [{ "type": "command", "command": "bun run <path>/LoadContext.ts" }],
258
+ "UserPromptSubmit": [{ "type": "command", "command": "bun run <path>/UserPromptOrchestrator.ts" }],
259
+ "PreToolUse": [
260
+ { "type": "command", "command": "bun run <path>/SecurityValidator.ts", "matcher": "Bash" },
261
+ { "type": "command", "command": "bun run <path>/SkillGuard.ts", "matcher": "Skill" }
262
+ ],
263
+ "Stop": [{ "type": "command", "command": "bun run <path>/StopOrchestrator.ts" }]
264
+ }
265
+ }
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Memory System Architecture
271
+
272
+ ### Directory Structure
273
+
274
+ ```
275
+ memory/
276
+ ├── state/ # Runtime state
277
+ │ ├── sessions.json # Session registry (name, cwd, status, summary)
278
+ │ ├── projects.json # Multi-session project tracking
279
+ │ ├── counts.json # Cached counts for greeting
280
+ │ ├── last-responses.json # Cached responses for rating correlation
281
+ │ ├── pending-failure.json # Deferred failure capture
282
+ │ └── debug.log # Hook execution logs
283
+
284
+ ├── signals/ # User feedback
285
+ │ └── ratings.jsonl # Explicit + implicit ratings
286
+
287
+ ├── relationship/ # Interaction tracking
288
+ │ ├── YYYY-MM/
289
+ │ │ └── YYYY-MM-DD.md # Daily notes (W/O/B format)
290
+ │ ├── opinions.json # Confidence-tracked opinions
291
+ │ └── reflections/ # Periodic reflection reports
292
+
293
+ ├── session-learning/ # Per-session learnings
294
+ │ └── YYYY-MM/
295
+ │ └── YYYY-MM-DD_title.md # Session learning with frontmatter
296
+
297
+ ├── failures/ # Low-rating context dumps
298
+ │ └── YYYY-MM/
299
+ │ └── YYYY-MM-DD_context.md # Failed session context for avoidance
300
+
301
+ ├── wisdom/ # Crystallized principles
302
+ │ └── frames/
303
+ │ └── domain.md # Domain-specific principles with confidence
304
+
305
+ └── synthesis/ # Pattern aggregation
306
+ └── YYYY-MM/
307
+ └── YYYY-MM-DD_period.md # Weekly/monthly synthesis reports
308
+ ```
309
+
310
+ ### Data Flow
311
+
312
+ ```
313
+ Session interaction
314
+
315
+ ├─► [Stop] Rating capture ──► signals/ratings.jsonl
316
+
317
+ ├─► [Stop] Relationship extraction (Haiku) ──► relationship/YYYY-MM/YYYY-MM-DD.md
318
+
319
+ ├─► [Stop] Work learning capture ──► session-learning/YYYY-MM/...
320
+
321
+ ├─► [Stop] Failure capture (low ratings) ──► failures/YYYY-MM/...
322
+
323
+ ├─► [Periodic] Reflect trigger ──► relationship/opinions.json
324
+ │ relationship/reflections/...
325
+
326
+ ├─► [Periodic] Synthesis ──► synthesis/YYYY-MM/...
327
+
328
+ └─► [Periodic] Wisdom graduation ──► wisdom/frames/...
329
+ ```
330
+
331
+ ### Relationship Note Format
332
+
333
+ Three note types, captured via Haiku inference at session end:
334
+
335
+ ```
336
+ W — World facts (user's situation, projects, tools)
337
+ O(c=0.85) — Opinions/preferences with confidence
338
+ B(c=0.75) — Beliefs/behavioral patterns with confidence
339
+ ```
340
+
341
+ ### Opinion Lifecycle
342
+
343
+ ```
344
+ Relationship notes (O/B types)
345
+
346
+ ├─► Reflect tool groups similar notes
347
+ │ ├─► 2+ occurrences → new opinion at 50% confidence
348
+ │ └─► Matches existing → +2% supporting evidence
349
+
350
+ ├─► AI confirmation → +10% (via tool:opinion)
351
+ ├─► AI contradiction → -20% (via tool:opinion)
352
+
353
+ └─► At ≥85% confidence → auto-injected into session context
354
+ ```
355
+
356
+ ---
357
+
358
+ ## Context Loading Architecture
359
+
360
+ ### Two-Layer Design
361
+
362
+ **Static context** (loaded natively by the agent):
363
+ - CLAUDE.md — identity, modes, context routing table
364
+ - Loaded once at session start, always available
365
+
366
+ **Dynamic context** (injected by LoadContext hook):
367
+ - Changes per-session, can't live in a static file
368
+ - Injected as `<system-reminder>` block to stdout
369
+ - Each section independently toggleable in `pal-settings.json → dynamicContext`
370
+
371
+ ### Injection Order
372
+
373
+ ```
374
+ LoadContext.ts
375
+
376
+ ├─► Regenerate CLAUDE.md if template/telos changed
377
+
378
+ └─► Build system-reminder:
379
+ 1. loadAtStartup files (user-configured)
380
+ 2. Crystallized principles (wisdom frames)
381
+ 3. Tracked opinions (≥85% confidence)
382
+ 4. Recent interaction notes (last 2 days)
383
+ 5. Learning digest (this project + other recent)
384
+ 6. Pattern synthesis recommendations
385
+ 7. Signal trends (today/week/trend)
386
+ 8. Failure patterns (last 5 low-rating contexts)
387
+ 9. Active work summary (sessions + projects)
388
+ ```
389
+
390
+ ### On-Demand Context
391
+
392
+ Everything else loads via the routing table in CLAUDE.md. The AI reads files only when the current task requires that context — no upfront loading of the full system.
393
+
394
+ ---
395
+
396
+ ## Security Architecture
397
+
398
+ ### Fail-Open Design
399
+
400
+ `SecurityValidator.ts` runs on PreToolUse for Bash commands. It blocks known-dangerous patterns but never prevents legitimate work:
401
+
402
+ - **Blocked**: `rm -rf /`, `chmod 777`, known secret file paths, command injection patterns
403
+ - **Allowed**: Everything else passes through
404
+ - **On error**: The hook exits silently — a broken security hook never blocks the user
405
+
406
+ ### What's Protected
407
+
408
+ - Dangerous shell commands (recursive deletes, permission changes)
409
+ - Known secret file paths (.env, credentials, key files)
410
+ - Command injection patterns in arguments
411
+
412
+ ### What's NOT Protected
413
+
414
+ PAL does not implement:
415
+ - Network-level security (no firewall, no proxy)
416
+ - File encryption (memory is plaintext on disk)
417
+ - Access control (anyone with filesystem access can read memory)
418
+
419
+ Users are responsible for securing their own machine and API keys.
420
+
421
+ ---
422
+
423
+ ## Cross-Platform Architecture
424
+
425
+ ### Agent Abstraction
426
+
427
+ ```
428
+ src/targets/
429
+ ├── claude/ # Claude Code specific
430
+ │ ├── install.ts # Register hooks + skills in ~/.claude/settings.json
431
+ │ └── uninstall.ts
432
+ ├── opencode/ # opencode specific
433
+ │ ├── install.ts # Register hooks + skills in opencode config
434
+ │ ├── uninstall.ts
435
+ │ └── plugin.ts # opencode plugin interface
436
+ └── lib.ts # Shared: JSON read/write, settings merge, TELOS scaffold
437
+ ```
438
+
439
+ ### Path Resolution
440
+
441
+ All paths resolve through `src/hooks/lib/paths.ts`:
442
+
443
+ | Path | Default | Override |
444
+ |------|---------|----------|
445
+ | PAL home | `~/.agents/PAL` | `PAL_HOME` |
446
+ | PAL package | Auto-detected from source | `PAL_PKG` |
447
+ | Claude config | `~/.claude` | `PAL_CLAUDE_DIR` |
448
+ | opencode config | `~/.config/opencode` | `PAL_OPENCODE_DIR` |
449
+ | Agents dir | `~/.agents` | `PAL_AGENTS_DIR` |
450
+
451
+ ### Portability Contract
452
+
453
+ - Core logic (`src/hooks/lib/`, `src/tools/`) has zero agent-specific imports
454
+ - Agent-specific code lives only in `src/targets/`
455
+ - Skills reference no agent-specific APIs
456
+ - Memory format is plain JSON/JSONL/Markdown — readable by any tool
457
+
458
+ ---
459
+
460
+ ## File Naming Conventions
461
+
462
+ | Type | Convention | Example |
463
+ |------|------------|---------|
464
+ | Skill directory | kebab-case | `extract-wisdom/`, `first-principles/` |
465
+ | SKILL.md | Uppercase | `SKILL.md` |
466
+ | Hook files | PascalCase | `LoadContext.ts`, `StopOrchestrator.ts` |
467
+ | Handler files | kebab-case | `session-name.ts`, `work-learning.ts` |
468
+ | Library files | kebab-case | `text-similarity.ts`, `signal-trends.ts` |
469
+ | Tool files | kebab-case | `relationship-reflect.ts`, `token-cost.ts` |
470
+ | Memory files | date-prefixed | `2026-03-24.md`, `2026-03-24_weekly.md` |
471
+ | Template files | UPPER_SNAKE | `ALGORITHM.md`, `CONTEXT_ROUTING.md` |
@@ -0,0 +1,32 @@
1
+ {
2
+ "identity": {
3
+ "ai": {
4
+ "name": "",
5
+ "fullName": "",
6
+ "displayName": "",
7
+ "catchphrase": ""
8
+ },
9
+ "principal": {
10
+ "name": "",
11
+ "timezone": ""
12
+ }
13
+ },
14
+ "loadAtStartup": {
15
+ "_docs": "Files force-loaded into session context at startup. Injected as <system-reminder> blocks.",
16
+ "files": [
17
+ "~/.agents/PAL/STEERING_RULES.md",
18
+ "~/.agents/PAL/telos/PROJECTS.md"
19
+ ]
20
+ },
21
+ "dynamicContext": {
22
+ "_docs": "Dynamic context sections injected at session start. Set to false to disable.",
23
+ "wisdom": true,
24
+ "opinions": true,
25
+ "relationship": true,
26
+ "learningDigest": true,
27
+ "synthesis": true,
28
+ "signalTrends": true,
29
+ "failurePatterns": true,
30
+ "activeWork": true
31
+ }
32
+ }
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Read",
5
- "Grep",
6
- "Glob",
4
+ "Read(//*)",
5
+ "Grep(//*)",
6
+ "Glob(//*)",
7
7
  "WebFetch",
8
8
  "WebSearch",
9
- "Bash(cat *)",
10
- "Bash(head *)",
11
- "Bash(tail *)",
12
- "Bash(ls *)",
13
- "Bash(find *)",
9
+ "Bash(cat //*)",
10
+ "Bash(head //*)",
11
+ "Bash(tail //*)",
12
+ "Bash(ls //*)",
13
+ "Bash(find //*)",
14
14
  "Bash(grep *)",
15
- "Bash(rg *)",
15
+ "Bash(rg //*)",
16
16
  "Bash(wc *)",
17
- "Bash(diff *)",
18
- "Bash(which *)",
19
- "Bash(file *)",
20
- "Bash(stat *)",
21
- "Bash(readlink *)",
17
+ "Bash(diff //*)",
18
+ "Bash(which //*)",
19
+ "Bash(file //*)",
20
+ "Bash(stat //*)",
21
+ "Bash(readlink //*)",
22
22
  "Bash(bun ~/.agents/skills/*/tools/*.ts *)"
23
23
  ]
24
24
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portable-agent-layer",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "PAL — Portable Agent Layer: persistent personal context for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,10 +42,9 @@
42
42
  "check-write": "biome check --write",
43
43
  "lint-staged": "lint-staged",
44
44
  "prepare": "husky",
45
- "install:all": "bun run src/cli/install.ts",
46
- "uninstall": "bun run src/cli/uninstall.ts",
45
+ "install:all": "bun run src/cli/index.ts cli install",
46
+ "uninstall": "bun run src/cli/index.ts cli uninstall",
47
47
  "tool:analyze": "bun run src/tools/analyze.ts",
48
- "tool:opinion": "bun run src/tools/opinion.ts",
49
48
  "tool:reflect": "bun run src/tools/relationship-reflect.ts",
50
49
  "tool:export": "bun run src/tools/export.ts",
51
50
  "tool:import": "bun run src/tools/import.ts",
@@ -73,6 +72,7 @@
73
72
  "typescript": "^5.9.0"
74
73
  },
75
74
  "dependencies": {
75
+ "@clack/prompts": "^1.1.0",
76
76
  "adm-zip": "^0.5.16"
77
77
  }
78
78
  }
package/src/cli/index.ts CHANGED
@@ -425,6 +425,13 @@ async function init(args: string[]) {
425
425
  }
426
426
 
427
427
  async function install(targets: { claude: boolean; opencode: boolean }) {
428
+ // Scaffold TELOS + PAL settings, then prompt for missing identity
429
+ const { scaffoldTelos, scaffoldPalSettings } = await import("../targets/lib");
430
+ const { promptIdentity } = await import("./setup-identity");
431
+ scaffoldTelos();
432
+ scaffoldPalSettings();
433
+ await promptIdentity();
434
+
428
435
  if (targets.claude) {
429
436
  console.log("━━━ Claude Code ━━━");
430
437
  await import("../targets/claude/install");