portable-agent-layer 0.57.0 → 0.58.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/assets/STATUSLINE.md +8 -4
- package/assets/agents/skill-author.md +54 -0
- package/assets/skills/create-skill/SKILL.md +15 -52
- package/assets/skills/create-skill/authoring-guide.md +46 -0
- package/package.json +1 -1
- package/src/cli/index.ts +1 -0
- package/src/cli/skill.ts +11 -1
- package/src/hooks/lib/agent.ts +1 -1
- package/src/hooks/lib/models.ts +21 -0
- package/src/targets/lib.ts +19 -3
package/assets/STATUSLINE.md
CHANGED
|
@@ -71,18 +71,22 @@ On Cursor, session cost and rate limits are usually absent from stdin — the sc
|
|
|
71
71
|
|
|
72
72
|
### On Windows
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
The installer does this automatically. To wire it manually, copy `statusline.ps1` to
|
|
75
|
+
`~/.claude/statusline.ps1` and add to `~/.claude/settings.json`:
|
|
75
76
|
```json
|
|
76
77
|
{
|
|
77
78
|
"statusLine": {
|
|
78
79
|
"type": "command",
|
|
79
|
-
"command": "powershell -NoProfile -
|
|
80
|
+
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File ~/.claude/statusline.ps1",
|
|
80
81
|
"padding": 2
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
```
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
`-ExecutionPolicy Bypass` (which must precede `-File`) lets the unsigned script run under a
|
|
87
|
+
`Restricted`/`AllSigned` machine policy — the common reason the status line silently fails to
|
|
88
|
+
appear. It does **not** override a policy enforced via Group Policy (`MachinePolicy`/`UserPolicy`);
|
|
89
|
+
run `Get-ExecutionPolicy -List` to check the scope, and if it's a GPO scope, that case needs IT.
|
|
86
90
|
|
|
87
91
|
The statusline script is at: `portable-agent-layer/assets/statusline.ps1`
|
|
88
92
|
|
|
@@ -104,7 +108,7 @@ The statusline script is at: `portable-agent-layer/assets/statusline.ps1`
|
|
|
104
108
|
## Dependencies
|
|
105
109
|
|
|
106
110
|
- **macOS/Linux:** `bash`, `jq`, `git` (for branch detection)
|
|
107
|
-
- **Windows:** PowerShell 7
|
|
111
|
+
- **Windows:** Windows PowerShell 5.1 (invoked as `powershell`; the script is 5.1-compatible) or PowerShell 7, `git` (for branch detection)
|
|
108
112
|
|
|
109
113
|
## Customization
|
|
110
114
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-author
|
|
3
|
+
description: Authors a new personal PAL skill end-to-end — writes the SKILL.md (and any tools), links it into every installed agent, and runs the doctor. Invoked by the create-skill skill to delegate the creative authoring to a flagship model.
|
|
4
|
+
|
|
5
|
+
claude:
|
|
6
|
+
tools: Bash, Read, Write, Edit, Grep, Glob
|
|
7
|
+
model: fable
|
|
8
|
+
|
|
9
|
+
opencode:
|
|
10
|
+
mode: subagent
|
|
11
|
+
permission:
|
|
12
|
+
read: allow
|
|
13
|
+
write: allow
|
|
14
|
+
edit: allow
|
|
15
|
+
bash: allow
|
|
16
|
+
|
|
17
|
+
cursor:
|
|
18
|
+
model: inherit
|
|
19
|
+
readonly: false
|
|
20
|
+
is_background: false
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
You author a single new personal skill for this user. You are handed a **skill name** and a **skill description**, and optionally hints about tooling or triggers.
|
|
24
|
+
|
|
25
|
+
## Steps
|
|
26
|
+
|
|
27
|
+
1. Read the authoring guide — it is the single source of truth for what a good skill is and the exact anatomy to follow:
|
|
28
|
+
```bash
|
|
29
|
+
cat ~/.pal/skills/create-skill/authoring-guide.md
|
|
30
|
+
```
|
|
31
|
+
2. Validate the name: lowercase-kebab, no spaces, not colliding with an existing skill (check `~/.pal/skills/` and the active skill list). If it collides or is malformed, stop and report the conflict instead of overwriting.
|
|
32
|
+
3. Create the skill and write its `SKILL.md`, populated per the guide's anatomy (frontmatter + Workflow + Output format + When to use):
|
|
33
|
+
```bash
|
|
34
|
+
mkdir -p ~/.pal/skills/<name>
|
|
35
|
+
```
|
|
36
|
+
4. If the skill needs runtime tooling, scaffold a `tools/` subdir alongside `SKILL.md` and write the scripts there.
|
|
37
|
+
5. Link the skill into every installed agent:
|
|
38
|
+
```bash
|
|
39
|
+
pal cli skill link <name>
|
|
40
|
+
```
|
|
41
|
+
6. Run the doctor and fix every `✗` error it reports; weigh each `⚠`:
|
|
42
|
+
```bash
|
|
43
|
+
pal cli skill doctor <name>
|
|
44
|
+
```
|
|
45
|
+
A name/folder mismatch or a misnamed file makes the skill silently fail to load — never skip this.
|
|
46
|
+
7. Hand-check what the doctor can't: trigger clarity, step concreteness (every step has a verb and an object), output specification, and scope discipline (one skill, one job).
|
|
47
|
+
|
|
48
|
+
## Output
|
|
49
|
+
|
|
50
|
+
Return, concisely:
|
|
51
|
+
- The path of the created `SKILL.md` (under `~/.pal/skills/<name>/`).
|
|
52
|
+
- The agents it was linked into (from the `pal cli skill link` output).
|
|
53
|
+
- The doctor's final result (errors resolved).
|
|
54
|
+
- A 2-3 sentence summary of the trigger and workflow, and how to invoke it.
|
|
@@ -8,65 +8,28 @@ argument-hint: <skill name> <skill description>
|
|
|
8
8
|
|
|
9
9
|
This scaffolds a personal skill into the user's own `~/.pal/skills/<name>/` and links it into every installed agent so it is immediately discoverable.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The quality rules and the exact skill anatomy live in one place — read them before writing anything:
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
2. **One skill, one job.** A skill describes a single workflow. If it needs branches like "for case A do X, for case B do Y," it is two skills.
|
|
16
|
-
|
|
17
|
-
3. **Concise and concrete.** Assume the model is already smart — only add what it doesn't already know. Every step has a verb and an object; no "as needed" or "appropriately." Keep the SKILL.md body well under 500 lines; push long reference material into sibling files linked one level deep.
|
|
18
|
-
|
|
19
|
-
A personal skill **may** contain this user's own context — their paths, project names, preferences, conventions. That is the point of a personal skill.
|
|
20
|
-
|
|
21
|
-
## Skill anatomy
|
|
22
|
-
|
|
23
|
-
```markdown
|
|
24
|
-
---
|
|
25
|
-
name: <slug> # the slash-command name; lowercase-kebab
|
|
26
|
-
description: <what it does + WHEN to invoke> # the dispatcher matches on this
|
|
27
|
-
argument-hint: <args> # optional; how the user passes input
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Overview / Workflow
|
|
31
|
-
|
|
32
|
-
Numbered, concrete steps the assistant follows on invocation.
|
|
33
|
-
|
|
34
|
-
## Output format
|
|
35
|
-
|
|
36
|
-
Exactly what the assistant returns — structure if it will be parsed, tone if a human reads it.
|
|
37
|
-
|
|
38
|
-
## When to use / Do NOT use
|
|
39
|
-
|
|
40
|
-
Two short lists; the "do not" list disambiguates this skill from neighbours.
|
|
13
|
+
```bash
|
|
14
|
+
cat ~/.pal/skills/create-skill/authoring-guide.md
|
|
41
15
|
```
|
|
42
16
|
|
|
43
|
-
The `description` should state **both what the skill does and when to invoke it**, in third person, with the trigger terms a model would match on. A vague description ("helps with documents") will not trigger reliably.
|
|
44
|
-
|
|
45
17
|
## Workflow when invoked with `<name> <description>`
|
|
46
18
|
|
|
47
|
-
1.
|
|
48
|
-
2. Confirm the trigger with the user if the description is ambiguous about *when* the skill should fire.
|
|
49
|
-
3. Create the directory and SKILL.md at the user's PAL home:
|
|
50
|
-
```bash
|
|
51
|
-
mkdir -p ~/.pal/skills/<name>
|
|
52
|
-
```
|
|
53
|
-
Write `~/.pal/skills/<name>/SKILL.md` populated from the anatomy above (frontmatter + Workflow + Output format + When to use).
|
|
54
|
-
4. If the skill needs runtime tooling, scaffold a `tools/` subdir alongside SKILL.md and write the scripts there.
|
|
55
|
-
5. Link the new skill into every installed agent so it is discoverable:
|
|
56
|
-
```bash
|
|
57
|
-
pal cli skill link <name>
|
|
58
|
-
```
|
|
59
|
-
This creates the per-skill discovery symlink in each installed agent's skills directory (Claude Code, Cursor, Copilot, Codex); opencode discovers it automatically via `~/.pal/skills/`.
|
|
60
|
-
6. Run the doctor and resolve every error it reports:
|
|
19
|
+
1. Check whether a flagship authoring model is configured for the current agent:
|
|
61
20
|
```bash
|
|
62
|
-
pal cli skill
|
|
21
|
+
pal cli skill author-model
|
|
63
22
|
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
23
|
+
2. **If it prints a model** → delegate the authoring to the `skill-author` subagent. That subagent is preconfigured to run on that flagship model; hand it the skill name, description, and any trigger/tooling hints, and let it write the SKILL.md, scaffold tools, run `pal cli skill link`, and run the doctor. Relay its result.
|
|
24
|
+
3. **If it prints nothing** → author the skill inline yourself:
|
|
25
|
+
- Read `authoring-guide.md` (above) and follow its anatomy.
|
|
26
|
+
- `mkdir -p ~/.pal/skills/<name>` and write `~/.pal/skills/<name>/SKILL.md`.
|
|
27
|
+
- If the skill needs runtime tooling, scaffold a `tools/` subdir and write the scripts there.
|
|
28
|
+
- Link it into every installed agent: `pal cli skill link <name>`.
|
|
29
|
+
- Run `pal cli skill doctor <name>` and fix every `✗`; weigh each `⚠`.
|
|
30
|
+
- Hand-check the items the doctor can't judge (see the guide's final section).
|
|
31
|
+
|
|
32
|
+
Either path: validate the name first (lowercase-kebab, no spaces, not colliding with an existing skill in `~/.pal/skills/` or the active skill list), and confirm the trigger with the user if the description is ambiguous about *when* the skill should fire.
|
|
70
33
|
|
|
71
34
|
## Output format
|
|
72
35
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Skill authoring guide
|
|
2
|
+
|
|
3
|
+
The canonical rules for authoring a personal PAL skill. Both the `create-skill`
|
|
4
|
+
dispatcher and the delegated `skill-author` subagent follow this file, so it is
|
|
5
|
+
the single source of truth for skill quality.
|
|
6
|
+
|
|
7
|
+
## What makes a good skill
|
|
8
|
+
|
|
9
|
+
1. **Pointed at the assistant, not the user.** A skill is *instructions you (the assistant) follow*. Write in second person addressing yourself ("read X", "run Y", "output Z"). Prescriptive verbs, deterministic flow — not a tutorial or marketing blurb.
|
|
10
|
+
|
|
11
|
+
2. **One skill, one job.** A skill describes a single workflow. If it needs branches like "for case A do X, for case B do Y," it is two skills.
|
|
12
|
+
|
|
13
|
+
3. **Concise and concrete.** Assume the model is already smart — only add what it doesn't already know. Every step has a verb and an object; no "as needed" or "appropriately." Keep the SKILL.md body well under 500 lines; push long reference material into sibling files linked one level deep.
|
|
14
|
+
|
|
15
|
+
A personal skill **may** contain this user's own context — their paths, project names, preferences, conventions. That is the point of a personal skill.
|
|
16
|
+
|
|
17
|
+
## Skill anatomy
|
|
18
|
+
|
|
19
|
+
```markdown
|
|
20
|
+
---
|
|
21
|
+
name: <slug> # the slash-command name; lowercase-kebab
|
|
22
|
+
description: <what it does + WHEN to invoke> # the dispatcher matches on this
|
|
23
|
+
argument-hint: <args> # optional; how the user passes input
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Overview / Workflow
|
|
27
|
+
|
|
28
|
+
Numbered, concrete steps the assistant follows on invocation.
|
|
29
|
+
|
|
30
|
+
## Output format
|
|
31
|
+
|
|
32
|
+
Exactly what the assistant returns — structure if it will be parsed, tone if a human reads it.
|
|
33
|
+
|
|
34
|
+
## When to use / Do NOT use
|
|
35
|
+
|
|
36
|
+
Two short lists; the "do not" list disambiguates this skill from neighbours.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `description` should state **both what the skill does and when to invoke it**, in third person, with the trigger terms a model would match on. A vague description ("helps with documents") will not trigger reliably.
|
|
40
|
+
|
|
41
|
+
## Hand-checks the doctor can't judge
|
|
42
|
+
|
|
43
|
+
- **Trigger clarity** — could a model decide *not* to invoke this from the description alone? If so, tighten it.
|
|
44
|
+
- **Step concreteness** — every step has a verb and an object.
|
|
45
|
+
- **Output specification** — the caller knows what they get back.
|
|
46
|
+
- **Scope discipline** — one skill, one job.
|
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -262,6 +262,7 @@ function showHelp() {
|
|
|
262
262
|
(search · graph · stats · hubs · find · show · add · ls)
|
|
263
263
|
pal cli skill link <name> Link a personal ~/.pal/skills/<name>/ into installed agents
|
|
264
264
|
pal cli skill doctor <name> Evaluate a skill against the authoring best practices
|
|
265
|
+
pal cli skill author-model Print the flagship model that authors skills for the active agent
|
|
265
266
|
pal cli debug [on|off] Enable/disable verbose hook debug logging (persisted)
|
|
266
267
|
|
|
267
268
|
Environment:
|
package/src/cli/skill.ts
CHANGED
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
* every installed agent so it is discoverable.
|
|
6
6
|
* pal cli skill doctor <name> Evaluate ~/.pal/skills/<name>/ against the
|
|
7
7
|
* skill-authoring best practices.
|
|
8
|
+
* pal cli skill author-model Print the flagship model configured to author
|
|
9
|
+
* skills for the active agent (empty if none).
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import { resolve } from "node:path";
|
|
13
|
+
import { getActiveAgent } from "../hooks/lib/agent";
|
|
14
|
+
import { flagshipAuthorModel } from "../hooks/lib/models";
|
|
11
15
|
import { palHome } from "../hooks/lib/paths";
|
|
12
16
|
import { linkPersonalSkill, log } from "../targets/lib";
|
|
13
17
|
import { formatReport, lintSkill } from "../tools/skill-doctor";
|
|
@@ -15,6 +19,12 @@ import { formatReport, lintSkill } from "../tools/skill-doctor";
|
|
|
15
19
|
export async function runSkill(args: string[]): Promise<number> {
|
|
16
20
|
const [sub, name] = args;
|
|
17
21
|
|
|
22
|
+
if (sub === "author-model") {
|
|
23
|
+
const model = flagshipAuthorModel(getActiveAgent());
|
|
24
|
+
if (model) console.log(model);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
if (sub === "doctor") {
|
|
19
29
|
if (!name) {
|
|
20
30
|
log.error("Usage: pal cli skill doctor <name>");
|
|
@@ -50,6 +60,6 @@ export async function runSkill(args: string[]): Promise<number> {
|
|
|
50
60
|
}
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
log.error("Usage: pal cli skill <link|doctor>
|
|
63
|
+
log.error("Usage: pal cli skill <link|doctor|author-model> [name]");
|
|
54
64
|
return 1;
|
|
55
65
|
}
|
package/src/hooks/lib/agent.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* vars are used as secondary fallbacks for environments that forward them.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
type AgentType = "claude" | "cursor" | "codex" | "copilot" | "opencode";
|
|
14
|
+
export type AgentType = "claude" | "cursor" | "codex" | "copilot" | "opencode";
|
|
15
15
|
|
|
16
16
|
const KNOWN_AGENTS: ReadonlySet<AgentType> = new Set([
|
|
17
17
|
"claude",
|
package/src/hooks/lib/models.ts
CHANGED
|
@@ -2,8 +2,29 @@
|
|
|
2
2
|
* Single source of truth for model IDs and pricing.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { AgentType } from "./agent";
|
|
6
|
+
|
|
5
7
|
export const HAIKU_MODEL = "claude-haiku-4-5-20251001";
|
|
6
8
|
export const SONNET_MODEL = "claude-sonnet-4-6";
|
|
9
|
+
export const FABLE_MODEL = "claude-fable-5";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Per-agent flagship model used to AUTHOR new skills (via `create-skill`).
|
|
13
|
+
*
|
|
14
|
+
* This is the single extension point for delegated skill authoring: an agent
|
|
15
|
+
* present here → `create-skill` spins up that agent's `skill-author` subagent on
|
|
16
|
+
* this model; an agent absent → `create-skill` authors inline. Add a provider by
|
|
17
|
+
* adding one entry (and a matching platform block in assets/agents/skill-author.md).
|
|
18
|
+
*/
|
|
19
|
+
export const FLAGSHIP_AUTHOR_MODEL: Partial<Record<AgentType, string>> = {
|
|
20
|
+
claude: FABLE_MODEL,
|
|
21
|
+
// codex: "gpt-5.5", // enable once Codex ships a tool-capable flagship subagent
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Flagship authoring model for an agent, or undefined if none is configured. */
|
|
25
|
+
export function flagshipAuthorModel(agent: AgentType): string | undefined {
|
|
26
|
+
return FLAGSHIP_AUTHOR_MODEL[agent];
|
|
27
|
+
}
|
|
7
28
|
|
|
8
29
|
/** Pricing per million tokens (USD) — from https://platform.claude.com/docs/en/about-claude/pricing */
|
|
9
30
|
export const MODEL_PRICING: Record<
|
package/src/targets/lib.ts
CHANGED
|
@@ -1042,7 +1042,7 @@ function statuslineCommand(target: StatuslineTarget): string {
|
|
|
1042
1042
|
: "~/.cursor/statusline.sh";
|
|
1043
1043
|
}
|
|
1044
1044
|
return isPlatformWin32
|
|
1045
|
-
? "powershell -NoProfile -File ~/.claude/statusline.ps1"
|
|
1045
|
+
? "powershell -NoProfile -ExecutionPolicy Bypass -File ~/.claude/statusline.ps1"
|
|
1046
1046
|
: "~/.claude/statusline.sh";
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
@@ -1105,6 +1105,23 @@ export function removeStatusline(target: StatuslineTarget = "claude"): boolean {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
}
|
|
1107
1107
|
|
|
1108
|
+
function isOldGetContentClaudeCommand(cmd: string): boolean {
|
|
1109
|
+
return cmd.includes("Get-Content -Raw");
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
function isPalWindowsClaudeCommandMissingBypass(cmd: string): boolean {
|
|
1113
|
+
return (
|
|
1114
|
+
process.platform === "win32" &&
|
|
1115
|
+
isPalStatuslineCommand(cmd, "claude") &&
|
|
1116
|
+
cmd.includes("powershell") &&
|
|
1117
|
+
!cmd.includes("-ExecutionPolicy Bypass")
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
function claudeStatuslineNeedsRefresh(cmd: string): boolean {
|
|
1122
|
+
return isOldGetContentClaudeCommand(cmd) || isPalWindowsClaudeCommandMissingBypass(cmd);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1108
1125
|
/** Add statusLine config if not already present or if using an old broken command */
|
|
1109
1126
|
export function addStatuslineConfig(
|
|
1110
1127
|
settings: Record<string, unknown>,
|
|
@@ -1115,8 +1132,7 @@ export function addStatuslineConfig(
|
|
|
1115
1132
|
if (statusLine && typeof statusLine === "object" && statusLine.command) {
|
|
1116
1133
|
const cmd = statusLine.command as string;
|
|
1117
1134
|
if (target === "claude") {
|
|
1118
|
-
|
|
1119
|
-
if (!cmd.includes("Get-Content -Raw")) {
|
|
1135
|
+
if (!claudeStatuslineNeedsRefresh(cmd)) {
|
|
1120
1136
|
return settings;
|
|
1121
1137
|
}
|
|
1122
1138
|
} else if (!isPalStatuslineCommand(cmd, "cursor")) {
|