feat: add coding-agent skill and anyBins gating
Co-authored-by: Sreekaran Srinath <ss@sreekaran.com>
This commit is contained in:
committed by
GitHub
parent
59601eb99c
commit
0ac30afb29
@@ -61,6 +61,7 @@ Fields under `metadata.clawdis`:
|
||||
- `homepage` — optional URL shown as “Website” in the macOS Skills UI.
|
||||
- `os` — optional list of platforms (`darwin`, `linux`, `win32`). If set, the skill is only eligible on those OSes.
|
||||
- `requires.bins` — list; each must exist on `PATH`.
|
||||
- `requires.anyBins` — list; at least one must exist on `PATH`.
|
||||
- `requires.env` — list; env var must exist **or** be provided in config.
|
||||
- `requires.config` — list of `clawdis.json` paths that must be truthy.
|
||||
- `primaryEnv` — env var name associated with `skills.entries.<name>.apiKey`.
|
||||
|
||||
78
skills/coding-agent/SKILL.md
Normal file
78
skills/coding-agent/SKILL.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: coding-agent
|
||||
description: Run Claude Code, Codex CLI, or OpenCode via tmux for resilient coding sessions.
|
||||
metadata: {"clawdis":{"emoji":"🧩","requires":{"bins":["tmux"],"anyBins":["claude","codex","opencode"]}}}
|
||||
---
|
||||
|
||||
# Coding Agent (tmux-first)
|
||||
|
||||
Use **tmux** for all coding-agent CLIs. Keep sessions resumable and logs visible.
|
||||
|
||||
## Quick preflight
|
||||
|
||||
```bash
|
||||
command -v claude codex opencode tmux
|
||||
```
|
||||
|
||||
If none of `claude`, `codex`, `opencode` exist, stop and ask to install.
|
||||
|
||||
## tmux baseline
|
||||
|
||||
```bash
|
||||
# Create or attach
|
||||
tmux new -A -s coding-agent
|
||||
|
||||
# Split panes
|
||||
tmux split-window -h
|
||||
tmux split-window -v
|
||||
|
||||
# Leave running, detach
|
||||
tmux detach
|
||||
```
|
||||
|
||||
## Claude Code
|
||||
|
||||
Interactive (preferred in tmux):
|
||||
- `claude` — start session
|
||||
- `claude -c` — continue most recent
|
||||
- `claude -r ""` — picker
|
||||
- `claude -r <session_id>` — resume specific
|
||||
|
||||
## Codex CLI
|
||||
|
||||
One-shot (safe in tmux):
|
||||
- `codex exec "Write a Python function that ..."`
|
||||
- `codex exec --model gpt-4o "Complex task"`
|
||||
- `codex exec --model o3 "Reasoning-heavy task"`
|
||||
|
||||
Interactive:
|
||||
- `codex "Your prompt"`
|
||||
- `codex resume`
|
||||
- `codex resume --last`
|
||||
- `codex resume --session <id>`
|
||||
|
||||
Apply changes:
|
||||
- `codex apply`
|
||||
|
||||
## OpenCode
|
||||
|
||||
One-shot:
|
||||
- `opencode run "Write a Python function that ..."`
|
||||
- `opencode run -m anthropic/claude-sonnet-4-5 "Complex task"`
|
||||
- `opencode run -m openai/gpt-5.2 "Coding task"`
|
||||
- `opencode run -m google/gemini-2.5-pro "Research task"`
|
||||
|
||||
Interactive:
|
||||
- `opencode`
|
||||
- `opencode -c`
|
||||
- `opencode -s <session-id>`
|
||||
|
||||
Session management:
|
||||
- `opencode session list`
|
||||
- `opencode export [sessionID]`
|
||||
- `opencode import <file>`
|
||||
|
||||
## Notes
|
||||
|
||||
- Prefer **tmux** even for one-shot runs; keep history + recovery.
|
||||
- For auth, run the tool’s login flow in tmux (`claude`, `codex login`, `opencode auth`).
|
||||
@@ -215,6 +215,12 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
description: "Needs a bin",
|
||||
metadata: '{"clawdis":{"requires":{"bins":["fakebin"]}}}',
|
||||
});
|
||||
await writeSkill({
|
||||
dir: path.join(skillsDir, "anybin-skill"),
|
||||
name: "anybin-skill",
|
||||
description: "Needs any bin",
|
||||
metadata: '{"clawdis":{"requires":{"anyBins":["missingbin","fakebin"]}}}',
|
||||
});
|
||||
await writeSkill({
|
||||
dir: path.join(skillsDir, "config-skill"),
|
||||
name: "config-skill",
|
||||
@@ -242,6 +248,7 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
expect(defaultPrompt).toContain("always-skill");
|
||||
expect(defaultPrompt).toContain("config-skill");
|
||||
expect(defaultPrompt).not.toContain("bin-skill");
|
||||
expect(defaultPrompt).not.toContain("anybin-skill");
|
||||
expect(defaultPrompt).not.toContain("env-skill");
|
||||
|
||||
await fs.mkdir(binDir, { recursive: true });
|
||||
@@ -258,6 +265,7 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
},
|
||||
});
|
||||
expect(gatedPrompt).toContain("bin-skill");
|
||||
expect(gatedPrompt).toContain("anybin-skill");
|
||||
expect(gatedPrompt).toContain("env-skill");
|
||||
expect(gatedPrompt).toContain("always-skill");
|
||||
expect(gatedPrompt).not.toContain("config-skill");
|
||||
|
||||
@@ -30,6 +30,7 @@ export type ClawdisSkillMetadata = {
|
||||
os?: string[];
|
||||
requires?: {
|
||||
bins?: string[];
|
||||
anyBins?: string[];
|
||||
env?: string[];
|
||||
config?: string[];
|
||||
};
|
||||
@@ -307,6 +308,7 @@ function resolveClawdisMetadata(
|
||||
requires: requiresRaw
|
||||
? {
|
||||
bins: normalizeStringList(requiresRaw.bins),
|
||||
anyBins: normalizeStringList(requiresRaw.anyBins),
|
||||
env: normalizeStringList(requiresRaw.env),
|
||||
config: normalizeStringList(requiresRaw.config),
|
||||
}
|
||||
@@ -347,6 +349,11 @@ function shouldIncludeSkill(params: {
|
||||
if (!hasBinary(bin)) return false;
|
||||
}
|
||||
}
|
||||
const requiredAnyBins = entry.clawdis?.requires?.anyBins ?? [];
|
||||
if (requiredAnyBins.length > 0) {
|
||||
const anyFound = requiredAnyBins.some((bin) => hasBinary(bin));
|
||||
if (!anyFound) return false;
|
||||
}
|
||||
|
||||
const requiredEnv = entry.clawdis?.requires?.env ?? [];
|
||||
if (requiredEnv.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user