portable-agent-layer 0.39.0 → 0.41.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 +37 -16
- package/assets/templates/PAL/MEMORY_SYSTEM.md +63 -17
- package/assets/templates/PAL/SYSTEM_ARCHITECTURE.md +81 -8
- package/assets/templates/hooks.copilot.json +4 -4
- package/assets/templates/settings.claude.json +7 -7
- package/package.json +8 -5
- package/src/cli/index.ts +282 -22
- package/src/cli/migrate.ts +5 -48
- package/src/hooks/CompactRecover.ts +4 -0
- package/src/hooks/LoadContext.ts +13 -8
- package/src/hooks/PreCompactPersist.ts +4 -0
- package/src/hooks/StopOrchestrator.ts +18 -6
- package/src/hooks/UserPromptOrchestrator.ts +7 -1
- package/src/hooks/handlers/auto-graduate.ts +8 -0
- package/src/hooks/handlers/failure-principle.ts +122 -0
- package/src/hooks/handlers/rating.ts +57 -26
- package/src/hooks/handlers/session-intelligence.ts +26 -6
- package/src/hooks/handlers/session-name.ts +13 -21
- package/src/hooks/lib/agent.ts +28 -13
- package/src/hooks/lib/detached-inference.ts +39 -0
- package/src/hooks/lib/graduation.ts +1 -0
- package/src/hooks/lib/inference.ts +786 -5
- package/src/hooks/lib/log.ts +60 -12
- package/src/hooks/lib/notify.ts +1 -0
- package/src/hooks/lib/projects.ts +52 -0
- package/src/hooks/lib/security.ts +5 -0
- package/src/hooks/lib/spawn-guard.ts +68 -0
- package/src/hooks/lib/stop.ts +77 -79
- package/src/targets/opencode/plugin.ts +13 -0
- package/src/tools/agent/project.ts +4 -42
- package/src/tools/self-model.ts +1 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A cross-platform, cross-agent layer for portable AI workflows, memory, and accumulated knowledge.
|
|
4
4
|
|
|
5
|
-
PAL lets you carry your agent context across **Windows**, **macOS**, and **Linux**, and work across different agent runtimes and interfaces such as **Claude Code**, **opencode**, **Cursor**, and **Codex**. Its core idea is simple: your knowledge and workflows should belong to **you**, not to a single machine, tool, or vendor.
|
|
5
|
+
PAL lets you carry your agent context across **Windows**, **macOS**, and **Linux**, and work across different agent runtimes and interfaces such as **Claude Code**, **opencode**, **Cursor**, **GitHub Copilot**, and **Codex**. Its core idea is simple: your knowledge and workflows should belong to **you**, not to a single machine, tool, or vendor.
|
|
6
6
|
|
|
7
7
|
> Inspired in part by [Daniel Miessler](https://danielmiessler.com)'s work on [Personal AI Infrastructure](https://github.com/danielmiessler/Personal_AI_Infrastructure). PAL is an independent open-source implementation focused on portability across platforms and agents. It is not affiliated with or endorsed by Daniel Miessler.
|
|
8
8
|
|
|
@@ -33,7 +33,7 @@ With PAL, you can:
|
|
|
33
33
|
> **Bun is required.** PAL is built on [Bun](https://bun.sh) and will not work with Node.js or other runtimes. Install it with `curl -fsSL https://bun.sh/install | bash`.
|
|
34
34
|
|
|
35
35
|
- [Bun](https://bun.sh) >= 1.3.0
|
|
36
|
-
- At least one of: [Claude Code](https://claude.ai/code), [opencode](https://opencode.ai), [Cursor](https://cursor.com), or [Codex](https://openai.com/index/introducing-codex/)
|
|
36
|
+
- At least one of: [Claude Code](https://claude.ai/code), [opencode](https://opencode.ai), [Cursor](https://cursor.com), [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli), or [Codex](https://openai.com/index/introducing-codex/)
|
|
37
37
|
|
|
38
38
|
### Package mode (recommended)
|
|
39
39
|
|
|
@@ -98,31 +98,36 @@ pal cli install # all available (default)
|
|
|
98
98
|
|
|
99
99
|
### Supported agents
|
|
100
100
|
|
|
101
|
-
| Agent | Support | Skills | Hooks | AGENTS.md | Subagents |
|
|
102
|
-
|
|
103
|
-
| Claude Code | Full | Yes | Yes | Yes | Yes |
|
|
104
|
-
| opencode | Full | Yes | Yes (plugin) | Yes | Yes |
|
|
105
|
-
| Cursor | Full | Yes | Yes | Yes (injected via hook) | Yes |
|
|
106
|
-
| GitHub Copilot | Full | Yes | Yes | Yes (via `~/.copilot/instructions/*.instructions.md`) | Yes |
|
|
107
|
-
| Codex |
|
|
101
|
+
| Agent | Support | Skills | Hooks | AGENTS.md | Subagents | Inference routing |
|
|
102
|
+
|-------|---------|--------|-------|-----------|-----------|-------------------|
|
|
103
|
+
| Claude Code | Full | Yes | Yes | Yes | Yes | `claude --print` |
|
|
104
|
+
| opencode | Full | Yes | Yes (plugin) | Yes | Yes | `opencode run` |
|
|
105
|
+
| Cursor | Full | Yes | Yes | Yes (injected via hook) | Yes | `cursor-agent` |
|
|
106
|
+
| GitHub Copilot | Full | Yes | Yes | Yes (via `~/.copilot/instructions/*.instructions.md`) | Yes | `copilot` |
|
|
107
|
+
| Codex | Full | Yes | Yes | Yes | No | `codex exec` |
|
|
108
|
+
|
|
109
|
+
PAL's background inference (session naming, summaries, failure capture, etc.) runs through whichever subscription CLI is active — no API key required by default.
|
|
108
110
|
|
|
109
111
|
---
|
|
110
112
|
|
|
111
113
|
## Environment variables
|
|
112
114
|
|
|
113
|
-
###
|
|
115
|
+
### API keys (all optional)
|
|
116
|
+
|
|
117
|
+
PAL routes inference through the host agent's subscription CLI by default. API keys are only needed as fallbacks when no CLI binary is available, or for skills that call non-Anthropic providers.
|
|
114
118
|
|
|
115
119
|
| Variable | Description |
|
|
116
120
|
|----------|-------------|
|
|
117
|
-
| `PAL_ANTHROPIC_API_KEY` |
|
|
121
|
+
| `PAL_ANTHROPIC_API_KEY` | Fallback for hook inference when no native CLI is available. Uses Haiku. |
|
|
122
|
+
| `PAL_OPENAI_API_KEY` | Fallback for hook inference when Codex is active without the `codex` binary, or when no Anthropic key is set. |
|
|
123
|
+
| `PAL_GEMINI_API_KEY` | For YouTube video analysis and web search skill |
|
|
124
|
+
| `PAL_XAI_API_KEY` | For Grok real-time research skill (X/web search) |
|
|
125
|
+
| `PAL_PERPLEXITY_API_KEY` | For Perplexity deep research skill |
|
|
118
126
|
|
|
119
|
-
###
|
|
127
|
+
### Path overrides
|
|
120
128
|
|
|
121
129
|
| Variable | Description |
|
|
122
130
|
|----------|-------------|
|
|
123
|
-
| `PAL_GEMINI_API_KEY` | For YouTube video analysis and web search skill |
|
|
124
|
-
| `PAL_XAI_API_KEY` | For Grok real-time research skill (X/web search) |
|
|
125
|
-
| `PAL_PERPLEXITY_API_KEY` | For Perplexity deep research skill |
|
|
126
131
|
| `PAL_HOME` | Override user state directory (default: `~/.pal` or repo root) |
|
|
127
132
|
| `PAL_PKG` | Override package root |
|
|
128
133
|
| `PAL_CLAUDE_DIR` | Override Claude config dir (default: `~/.claude`) |
|
|
@@ -132,6 +137,14 @@ pal cli install # all available (default)
|
|
|
132
137
|
| `PAL_CODEX_DIR` | Override Codex config dir (default: `~/.codex`) |
|
|
133
138
|
| `PAL_AGENTS_DIR` | Override agents dir (default: `~/.agents`) |
|
|
134
139
|
|
|
140
|
+
### Debug / test
|
|
141
|
+
|
|
142
|
+
| Variable | Description |
|
|
143
|
+
|----------|-------------|
|
|
144
|
+
| `PAL_DEBUG` | Set to `1` to emit verbose hook logs to `memory/state/debug.log` |
|
|
145
|
+
| `PAL_INFERENCE_DISABLED` | Set to `1` to disable all inference (used by the test suite to prevent real CLI spawns) |
|
|
146
|
+
| `PAL_NOTIFICATIONS_DISABLED` | Set to `1` to suppress desktop notifications (used by the test suite) |
|
|
147
|
+
|
|
135
148
|
---
|
|
136
149
|
|
|
137
150
|
## Skills
|
|
@@ -142,16 +155,23 @@ PAL ships with built-in skills that extend your agent's capabilities:
|
|
|
142
155
|
|-------|-------------|
|
|
143
156
|
| `analyze-pdf` | Download and analyze PDF files |
|
|
144
157
|
| `analyze-youtube` | Analyze YouTube videos using Gemini |
|
|
158
|
+
| `consulting-report` | Generate consulting-style reports as PDFs |
|
|
145
159
|
| `council` | Multi-perspective parallel debate on decisions |
|
|
160
|
+
| `create-pdf` | Render structured content into a PDF |
|
|
146
161
|
| `create-skill` | Scaffold a new skill from a description |
|
|
147
162
|
| `extract-entities` | Extract people and companies from content |
|
|
148
163
|
| `extract-wisdom` | Extract structured insights from content |
|
|
149
164
|
| `first-principles` | Break down problems to fundamentals |
|
|
150
165
|
| `fyzz-chat-api` | Query Fyzz Chat conversations via API |
|
|
166
|
+
| `opinion` | Confirm or contradict tracked opinions (confidence-weighted) |
|
|
167
|
+
| `presentation` | Build branded slide decks from outlines |
|
|
168
|
+
| `projects` | Look up, resume, register, or manage tracked projects |
|
|
151
169
|
| `reflect` | Diagnose why a PAL behavior didn't trigger |
|
|
152
170
|
| `research` | Multi-agent parallel research |
|
|
153
171
|
| `review` | Security-focused code review |
|
|
154
172
|
| `summarize` | Structured summarization |
|
|
173
|
+
| `telos` | Inspect or update goals, beliefs, strategies, narratives |
|
|
174
|
+
| `think` | Structured first-pass reasoning on a problem |
|
|
155
175
|
|
|
156
176
|
---
|
|
157
177
|
|
|
@@ -178,7 +198,8 @@ Your setup should be able to travel with you.
|
|
|
178
198
|
## Features
|
|
179
199
|
|
|
180
200
|
- **Cross-platform**: works on Windows, macOS, and Linux
|
|
181
|
-
- **Cross-agent**: full support for Claude Code, opencode, and
|
|
201
|
+
- **Cross-agent**: full support for Claude Code, opencode, Cursor, GitHub Copilot, and Codex (Codex still lacks subagents)
|
|
202
|
+
- **Subscription-first inference**: background inference routes through whichever subscription CLI is active — no API key needed by default
|
|
182
203
|
- **Portable knowledge**: export and import accumulated knowledge
|
|
183
204
|
- **TypeScript-first**: built in TypeScript from day one
|
|
184
205
|
- **Open source**: hackable, inspectable, extensible
|
|
@@ -1,26 +1,72 @@
|
|
|
1
1
|
# Memory System
|
|
2
2
|
|
|
3
|
-
PAL has its own memory system that persists across sessions AND across tools (Claude Code, opencode). Always prefer PAL memory over any tool-native memory system.
|
|
3
|
+
PAL has its own memory system that persists across sessions AND across tools (Claude Code, opencode, Cursor, Copilot, Codex). Always prefer PAL memory over any tool-native memory system.
|
|
4
|
+
|
|
5
|
+
## Layout
|
|
6
|
+
|
|
7
|
+
All memory lives under `~/.pal/memory/`:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
memory/
|
|
11
|
+
├── state/ # Runtime state (managed by hooks)
|
|
12
|
+
│ ├── sessions.json # Session registry
|
|
13
|
+
│ ├── counts.json # Cached counts for greeting
|
|
14
|
+
│ ├── last-responses.json # Cached responses for rating correlation
|
|
15
|
+
│ ├── pending-failure.json # Deferred failure capture
|
|
16
|
+
│ ├── captured-learnings.json # Session-intelligence dedup map
|
|
17
|
+
│ ├── session-names.json # Generated session titles
|
|
18
|
+
│ ├── debug.log[.1-.5] # Rotated hook execution logs
|
|
19
|
+
│ └── token-usage.jsonl # Per-call inference token usage
|
|
20
|
+
│
|
|
21
|
+
├── signals/
|
|
22
|
+
│ └── ratings.jsonl # Append-only rating signals (explicit + implicit)
|
|
23
|
+
│
|
|
24
|
+
├── relationship/
|
|
25
|
+
│ ├── YYYY-MM/YYYY-MM-DD.md # Daily interaction notes (W / O / B)
|
|
26
|
+
│ ├── opinions.json # Confidence-tracked opinions
|
|
27
|
+
│ └── reflections/ # Periodic reflection reports
|
|
28
|
+
│
|
|
29
|
+
├── self-model/
|
|
30
|
+
│ └── current.md # Synthesized self-model (auto-imported into CLAUDE.md)
|
|
31
|
+
│
|
|
32
|
+
├── learning/
|
|
33
|
+
│ ├── session/YYYY-MM/*.md # Per-session learnings with frontmatter
|
|
34
|
+
│ ├── failures/YYYY-MM/*.md # Low-rating context captures
|
|
35
|
+
│ ├── synthesis/YYYY-MM/*.md # Weekly/monthly synthesis reports
|
|
36
|
+
│ └── .retrieval-index.json # Embedding index for retrieval
|
|
37
|
+
│
|
|
38
|
+
├── wisdom/
|
|
39
|
+
│ ├── frames/<domain>.md # Crystallized principles per domain
|
|
40
|
+
│ └── state/ # Wisdom graduation bookkeeping
|
|
41
|
+
│
|
|
42
|
+
└── projects/
|
|
43
|
+
└── <slug>/ # Per-project history, threads, progress
|
|
44
|
+
```
|
|
4
45
|
|
|
5
46
|
## Where to write
|
|
6
47
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
48
|
+
Almost everything in `state/`, `signals/`, `relationship/opinions.json`, `learning/`, `wisdom/`, and `self-model/` is hook-managed — **never edit these directly**. Use the relevant skill or tool instead.
|
|
49
|
+
|
|
50
|
+
| You want to capture | Go through | Lands at |
|
|
51
|
+
|---------------------|------------|----------|
|
|
52
|
+
| A new validated principle | `skill: opinion` (confirm) or wisdom frame edit | `wisdom/frames/<domain>.md` |
|
|
53
|
+
| A daily observation about the user | Relationship note in algorithm LEARN phase | `relationship/YYYY-MM/YYYY-MM-DD.md` |
|
|
54
|
+
| A reusable session insight | Session-intelligence handler (automatic) | `learning/session/YYYY-MM/*.md` |
|
|
55
|
+
| A failure worth learning from | Failure-principle handler (automatic, low ratings) | `learning/failures/YYYY-MM/*.md` |
|
|
56
|
+
| A rating signal | UserPromptOrchestrator rating capture | `signals/ratings.jsonl` |
|
|
57
|
+
| A project handoff | Project skill / detached handlers | `projects/<slug>/` |
|
|
12
58
|
|
|
13
|
-
## Format
|
|
59
|
+
## Format conventions
|
|
14
60
|
|
|
15
|
-
- **Wisdom frames**: One `.md` file per domain
|
|
16
|
-
- **Relationship notes**: Daily `.md` file
|
|
17
|
-
- **Session learnings**:
|
|
18
|
-
- **Failure captures**: One
|
|
61
|
+
- **Wisdom frames**: One `.md` file per domain. Bullet-point principles, each tagged with a confidence value (e.g. `(85%)`). Append to existing files when possible; create a new domain only when none fits.
|
|
62
|
+
- **Relationship notes**: Daily `.md` file. Each bullet is typed: `W` (world fact), `O(c=0.85)` (opinion), or `B(c=0.75)` (behavior pattern), with a confidence in `c=...`.
|
|
63
|
+
- **Session learnings**: Frontmatter (`title`, `category`, `date`, `cwd`, optional `session`) + a body split into `## What Was Done` and `## Insights`.
|
|
64
|
+
- **Failure captures**: One `.md` per failure, named `{YYYYMMDD-HHmmss}_{slug}.md`, describing what went wrong, why, and what to do differently.
|
|
65
|
+
- **Synthesis reports**: One `.md` per period (`YYYY-MM-DD_weekly.md` etc.) aggregating recurring patterns from session learnings + failures.
|
|
19
66
|
|
|
20
|
-
## When to write
|
|
67
|
+
## When NOT to write
|
|
21
68
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- Do NOT write memories about trivial exchanges or things already captured in TELOS.
|
|
69
|
+
- Trivial exchanges (greetings, brief acknowledgments) → skip
|
|
70
|
+
- Anything already captured in TELOS → skip
|
|
71
|
+
- Anything that duplicates an existing wisdom frame or opinion → use the opinion skill to reinforce instead
|
|
72
|
+
- Anything the user has not validated yet — record it as a relationship note first, let it graduate naturally
|
|
@@ -227,12 +227,20 @@ Brief description.
|
|
|
227
227
|
└─────────────────────┘
|
|
228
228
|
|
|
229
229
|
┌─────────────────────┐
|
|
230
|
-
│ Stop │──► StopOrchestrator.ts
|
|
230
|
+
│ Stop │──► StopOrchestrator.ts → runStopHandlers()
|
|
231
|
+
│ │ Detached (inference-bearing, fire-and-forget):
|
|
232
|
+
│ │ - Session intelligence (title, summary, insights, handoff)
|
|
233
|
+
│ │ - Failure principle extraction (low ratings)
|
|
234
|
+
│ │ - Auto-graduate wisdom (24h TTL, idempotent)
|
|
235
|
+
│ │ Concurrent (Promise.allSettled):
|
|
231
236
|
│ │ - Work session capture
|
|
232
|
-
│ │ -
|
|
233
|
-
│ │ -
|
|
234
|
-
│ │ -
|
|
237
|
+
│ │ - Project touch / history
|
|
238
|
+
│ │ - Persist last exchange (handoff seed)
|
|
239
|
+
│ │ - Cache last response (rating correlation)
|
|
235
240
|
│ │ - Reflect trigger check
|
|
241
|
+
│ │ - Self-model trigger check
|
|
242
|
+
│ │ - Synthesis pipeline
|
|
243
|
+
│ │ - Desktop notify
|
|
236
244
|
│ │ - Write context digests (semi-static sources)
|
|
237
245
|
│ │ - Auto-backup
|
|
238
246
|
│ │ - Count updates
|
|
@@ -243,9 +251,11 @@ Brief description.
|
|
|
243
251
|
### Design Principles
|
|
244
252
|
|
|
245
253
|
- **Fail-open**: Hook errors never block the user's session
|
|
246
|
-
- **
|
|
247
|
-
- **
|
|
248
|
-
- **
|
|
254
|
+
- **Detached inference**: Long inference calls (session intelligence, failure principle, auto-graduate) spawn detached child processes that survive the hook returning. The parent hook exits in milliseconds — cold-start latency for the subscription CLI no longer blocks the next prompt.
|
|
255
|
+
- **Parallel execution**: Non-inference handlers run via `Promise.allSettled` — one failure doesn't block others
|
|
256
|
+
- **Idempotent**: Handlers check for existing state before writing (auto-graduate uses 24h TTL + content dedup; session intelligence dedups by message count)
|
|
257
|
+
- **Timeout-aware**: Inference calls have hard timeouts (60s default; longer because they run detached and don't block the user)
|
|
258
|
+
- **Race-safe**: Detached claim files use atomic `rename()` with ENOENT treated as a benign "already claimed" signal (opencode fires `session.idle` + `session.diff` concurrently)
|
|
249
259
|
- **Subagent-aware**: `LoadContext.ts` skips heavy context loading for subagent sessions
|
|
250
260
|
|
|
251
261
|
### Configuration
|
|
@@ -404,6 +414,66 @@ Everything else loads via the routing table in CLAUDE.md. The AI reads files onl
|
|
|
404
414
|
|
|
405
415
|
---
|
|
406
416
|
|
|
417
|
+
## Inference Routing Architecture
|
|
418
|
+
|
|
419
|
+
### Subscription-First Model
|
|
420
|
+
|
|
421
|
+
PAL's background inference (session naming, summaries, failure capture, wisdom graduation, etc.) routes through whichever subscription CLI is currently hosting the session. No API key is required by default — the user already pays for the subscription that comes with their agent.
|
|
422
|
+
|
|
423
|
+
### Routing Table
|
|
424
|
+
|
|
425
|
+
The active agent is detected via `getActiveAgent()` in `src/hooks/lib/agent.ts` (driven by the `PAL_AGENT` env var set per-target). The dispatcher in `src/hooks/lib/inference.ts` then routes to the matching CLI:
|
|
426
|
+
|
|
427
|
+
| Active agent | CLI invoked | Notes |
|
|
428
|
+
|--------------|-------------|-------|
|
|
429
|
+
| `claude` | `claude --print` | Inherits the user's Claude Code subscription |
|
|
430
|
+
| `opencode` | `opencode run` | Output parsed via `extractOpencodeText()` |
|
|
431
|
+
| `cursor` | `cursor-agent` | argv-only, no stdin |
|
|
432
|
+
| `copilot` | `copilot` | GitHub Copilot CLI |
|
|
433
|
+
| `codex` | `codex exec` | Falls back to `PAL_OPENAI_API_KEY` if the `codex` binary is missing |
|
|
434
|
+
|
|
435
|
+
If no CLI binary is available, the dispatcher falls back to `PAL_ANTHROPIC_API_KEY` (Haiku via the Anthropic API) or `PAL_OPENAI_API_KEY` (OpenAI API). `canInfer()` returns `false` only when both routes are unavailable — handlers then skip silently.
|
|
436
|
+
|
|
437
|
+
### Recursion Defense (Three Layers)
|
|
438
|
+
|
|
439
|
+
Spawning a CLI from inside a hook risks the child re-triggering the same hooks, leading to an infinite spawn loop. Three defenses, all active at once:
|
|
440
|
+
|
|
441
|
+
1. **CLI flags** — Mirrors PAI's pattern: `--setting-sources ''` and `--tools ''` strip the child of its hook config and tool access entirely (claude, opencode equivalents).
|
|
442
|
+
2. **Sentinel env var** — `PAL_SPAWNED_INFERENCE=1` is set on every spawn. Hook entry points call `exitIfSpawnedInference()` and bail before doing any work.
|
|
443
|
+
3. **Depth counter** — `PAL_SPAWN_DEPTH` increments per hop; the circuit breaks at `MAX_DEPTH=1`. Belt-and-suspenders for the above.
|
|
444
|
+
|
|
445
|
+
The `CLAUDECODE` env var is unset *scoped to the child process only* (not deleted from the parent's environment) so the spawned `claude` CLI doesn't think it's nested inside another Claude session.
|
|
446
|
+
|
|
447
|
+
### Detached Inference Pattern
|
|
448
|
+
|
|
449
|
+
Long inference calls (session intelligence, failure principle extraction, auto-graduate) run via `spawnDetachedInference()`. The parent hook writes the transcript to a tmp file, spawns a detached child with `--run <args>`, and returns immediately. The child reads the tmp file, runs inference, writes results to disk, and unlinks the tmp file.
|
|
450
|
+
|
|
451
|
+
```
|
|
452
|
+
StopOrchestrator
|
|
453
|
+
│
|
|
454
|
+
├─► detachSessionIntelligence(transcript, sessionId)
|
|
455
|
+
│ └─► [child] inference → session-learning/YYYY-MM/...
|
|
456
|
+
│
|
|
457
|
+
├─► detachFailurePrinciple(transcript)
|
|
458
|
+
│ ├─► Atomic claim: rename pending-failure.json → tmp/pending.json
|
|
459
|
+
│ │ (ENOENT means another concurrent Stop hook claimed it — benign)
|
|
460
|
+
│ └─► [child] inference → failures/YYYY-MM/...
|
|
461
|
+
│
|
|
462
|
+
└─► detachAutoGraduate()
|
|
463
|
+
└─► [child] 24h TTL + content dedup → wisdom/frames/...
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
The orchestrator returns in milliseconds; subscription-CLI cold-start latency no longer blocks the user's next prompt.
|
|
467
|
+
|
|
468
|
+
### Resilience
|
|
469
|
+
|
|
470
|
+
- **Empty-abort retry** — If a CLI returns an empty stdout (burst-concurrency race), retry once with 500–1500ms jitter
|
|
471
|
+
- **Test kill-switch** — `PAL_INFERENCE_DISABLED=1` (preloaded by `test/setup.ts`) short-circuits all inference so tests never spawn real CLIs
|
|
472
|
+
- **Per-call attribution** — Every inference call logs `caller=X sessionId=Y` so debug.log makes routing trivially auditable
|
|
473
|
+
- **Doctor probes** — `pal cli doctor` actually invokes each route and reports which agents are correctly wired
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
407
477
|
## Security Architecture
|
|
408
478
|
|
|
409
479
|
### Fail-Open Design
|
|
@@ -450,10 +520,13 @@ src/targets/
|
|
|
450
520
|
├── copilot/ # GitHub Copilot specific
|
|
451
521
|
│ ├── install.ts # Write instruction files + update VS Code settings
|
|
452
522
|
│ └── uninstall.ts
|
|
523
|
+
├── codex/ # Codex specific
|
|
524
|
+
│ ├── install.ts # Merge hooks into ~/.codex/hooks.json + skills + AGENTS.md
|
|
525
|
+
│ └── uninstall.ts
|
|
453
526
|
└── lib.ts # Shared: JSON read/write, settings merge, TELOS scaffold
|
|
454
527
|
```
|
|
455
528
|
|
|
456
|
-
|
|
529
|
+
All five targets install hooks, skills, and AGENTS.md. Codex does not yet support subagents.
|
|
457
530
|
|
|
458
531
|
### Path Resolution
|
|
459
532
|
|
|
@@ -10,23 +10,23 @@
|
|
|
10
10
|
"userPromptSubmitted": [
|
|
11
11
|
{
|
|
12
12
|
"type": "command",
|
|
13
|
-
"bash": "bun run {{PKG_ROOT}}/src/hooks/UserPromptOrchestrator.ts"
|
|
13
|
+
"bash": "PAL_AGENT=copilot bun run {{PKG_ROOT}}/src/hooks/UserPromptOrchestrator.ts"
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
16
|
"preToolUse": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"bash": "bun run {{PKG_ROOT}}/src/hooks/SecurityValidator.ts"
|
|
19
|
+
"bash": "PAL_AGENT=copilot bun run {{PKG_ROOT}}/src/hooks/SecurityValidator.ts"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"type": "command",
|
|
23
|
-
"bash": "bun run {{PKG_ROOT}}/src/hooks/SkillGuard.ts"
|
|
23
|
+
"bash": "PAL_AGENT=copilot bun run {{PKG_ROOT}}/src/hooks/SkillGuard.ts"
|
|
24
24
|
}
|
|
25
25
|
],
|
|
26
26
|
"agentStop": [
|
|
27
27
|
{
|
|
28
28
|
"type": "command",
|
|
29
|
-
"bash": "bun run {{PKG_ROOT}}/src/hooks/StopOrchestrator.ts"
|
|
29
|
+
"bash": "PAL_AGENT=copilot bun run {{PKG_ROOT}}/src/hooks/StopOrchestrator.ts"
|
|
30
30
|
}
|
|
31
31
|
]
|
|
32
32
|
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"hooks": [
|
|
31
31
|
{
|
|
32
32
|
"type": "command",
|
|
33
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/LoadContext.ts"
|
|
33
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/LoadContext.ts"
|
|
34
34
|
}
|
|
35
35
|
]
|
|
36
36
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"hooks": [
|
|
40
40
|
{
|
|
41
41
|
"type": "command",
|
|
42
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/CompactRecover.ts"
|
|
42
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/CompactRecover.ts"
|
|
43
43
|
}
|
|
44
44
|
]
|
|
45
45
|
}
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"hooks": [
|
|
51
51
|
{
|
|
52
52
|
"type": "command",
|
|
53
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/PreCompactPersist.ts"
|
|
53
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/PreCompactPersist.ts"
|
|
54
54
|
}
|
|
55
55
|
]
|
|
56
56
|
}
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"hooks": [
|
|
62
62
|
{
|
|
63
63
|
"type": "command",
|
|
64
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/UserPromptOrchestrator.ts"
|
|
64
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/UserPromptOrchestrator.ts"
|
|
65
65
|
}
|
|
66
66
|
]
|
|
67
67
|
}
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"hooks": [
|
|
73
73
|
{
|
|
74
74
|
"type": "command",
|
|
75
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/SecurityValidator.ts"
|
|
75
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/SecurityValidator.ts"
|
|
76
76
|
}
|
|
77
77
|
]
|
|
78
78
|
},
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"hooks": [
|
|
82
82
|
{
|
|
83
83
|
"type": "command",
|
|
84
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/SkillGuard.ts"
|
|
84
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/SkillGuard.ts"
|
|
85
85
|
}
|
|
86
86
|
]
|
|
87
87
|
}
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"hooks": [
|
|
93
93
|
{
|
|
94
94
|
"type": "command",
|
|
95
|
-
"command": "bun run {{PKG_ROOT}}/src/hooks/StopOrchestrator.ts"
|
|
95
|
+
"command": "PAL_AGENT=claude bun run {{PKG_ROOT}}/src/hooks/StopOrchestrator.ts"
|
|
96
96
|
}
|
|
97
97
|
]
|
|
98
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "portable-agent-layer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "PAL — Portable Agent Layer: persistent personal context for AI coding assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"check-write": "biome check --write",
|
|
43
43
|
"knip": "knip-bun",
|
|
44
44
|
"klint": "klint",
|
|
45
|
+
"jscpd": "jscpd src --noTips --silent",
|
|
46
|
+
"jscpd:report": "jscpd src --noTips",
|
|
45
47
|
"lint-staged": "lint-staged",
|
|
46
48
|
"prepare": "bun .husky/install.mjs",
|
|
47
49
|
"install:all": "bun run src/cli/index.ts cli install",
|
|
@@ -66,21 +68,22 @@
|
|
|
66
68
|
"@opencode-ai/plugin": "latest",
|
|
67
69
|
"@semantic-release/changelog": "^6.0.3",
|
|
68
70
|
"@semantic-release/git": "^10.0.1",
|
|
69
|
-
"@semantic-release/github": "^12.0.
|
|
71
|
+
"@semantic-release/github": "^12.0.8",
|
|
70
72
|
"@types/adm-zip": "^0.5.8",
|
|
71
73
|
"@types/bun": "latest",
|
|
72
74
|
"@types/node": "latest",
|
|
73
75
|
"husky": "^9.1.7",
|
|
74
|
-
"
|
|
76
|
+
"jscpd": "^4.2.3",
|
|
77
|
+
"knip": "^6.14.1",
|
|
75
78
|
"lint-staged": "^15.5.2",
|
|
76
79
|
"semantic-release": "^25.0.3",
|
|
77
80
|
"typescript": "^5.9.3"
|
|
78
81
|
},
|
|
79
82
|
"dependencies": {
|
|
80
|
-
"@clack/prompts": "^1.
|
|
83
|
+
"@clack/prompts": "^1.4.0",
|
|
81
84
|
"@konvert7/klint": "^0.2.0",
|
|
82
85
|
"adm-zip": "^0.5.17",
|
|
83
86
|
"marked": "^15.0.12",
|
|
84
|
-
"playwright": "^1.
|
|
87
|
+
"playwright": "^1.60.0"
|
|
85
88
|
}
|
|
86
89
|
}
|