Skip to content

Commit e470410

Browse files
committed
Restore the opsh skill 1:1 with GaaS
Replace the Corbits rewrite with Guy's GaaS body. Keep user-invocable: false so the skill stays use_skill-only. Tool and shell mapping stays on native-integration.
1 parent 4c0c661 commit e470410

4 files changed

Lines changed: 78 additions & 60 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ parallel copies under `docs/` or `scripts/notes/`. At cut time: rename
1919

2020
### Changed
2121

22+
- Restore the opsh skill 1:1 with GaaS. Tool/shell mapping stays on native-integration. user-invocable: false stays so it remains use_skill-only.
2223
- Restore the git-rebase skill body 1:1 with GaaS. Intern execution recipe stays on native-integration. user-invocable: false stays so it remains use_skill-only.
2324
- Restore the linear-issue-workflow skill body 1:1 with GaaS. Claim-first, In Review, and git-worktrees extras stay on native-integration. user-invocable: false stays so it remains use_skill-only.
2425
- Restore the interview skill body 1:1 with GaaS (AskUserQuestion). Operator-ask mapping stays on native-integration. Slash /interview remains.

plugins/corbits-skills/skills/native-integration/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Do not delete Corbits-only skills (`plan`, `git-worktrees`, `idiot-proof`). They
1616

1717
Corbits tests use `bun:test` (`bun test`, `bun run test`), not GaaS `tap` (`import t from "tap"`). When the typescript skill shows tap examples, map them to bun:test (`import { expect, test } from "bun:test"`). Do not fork the typescript skill body.
1818

19+
GaaS opsh scripts are bash (`#!/usr/bin/env opsh`, `lib::import`) and use TAP via `prove` (`test-harness`). That harness is not Corbits `bun:test`. Write scripts with `write_file`/`edit_file`; agent commands use `run_shell`. Do not fork the GaaS opsh body.
20+
1921
## Tool mapping
2022

2123
When a GaaS skill names a Claude/GaaS tool, use the Corbits equivalent. Do not call the GaaS name.

plugins/corbits-skills/skills/opsh/SKILL.md

Lines changed: 56 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
---
22
name: opsh
3+
description: Write scripts using opsh and its built-in libraries. Load this skill when writing, reviewing, or debugging opsh scripts.
34
user-invocable: false
4-
description: Write scripts using opsh and its built-in libraries. Tiny scripts: DIY with these rules. Substantial script work: copy the rules into an implement brief. Load when writing, reviewing, or debugging opsh scripts.
55
---
66

77
# opsh Scripting
88

9-
How to write scripts with opsh and its libraries. Tiny / single-file scripts: DIY with write_file/edit_file using these rules. Substantial script work: spawn `spawn_agent(agent="builder")` with these rules copied into the brief, then collect with `wait_agents` (workers do not mount `use_skill`). For a review, spawn `spawn_agent(agent="critic")` (or `spawn_agent(agent="neckbeard")` for hygiene-only) with the same rules copied in, then `wait_agents`.
10-
11-
Shell for agent commands is `run_shell`. Bash-the-language in the examples below stays — opsh scripts are bash.
12-
139
opsh is a scripting environment for operations use. It is a curated bash
1410
environment with sensible defaults and a standard library. Scripts are
1511
bash, but opsh sets strict runtime options and provides a library
@@ -39,14 +35,14 @@ lib::import git
3935

4036
opsh sets these options before your script runs. Do not disable them.
4137

42-
| Setting | Effect |
43-
| -------------------------- | ------------------------------------------------ |
44-
| `set -e` (errexit) | Non-zero return terminates unless caught |
45-
| `set -u` (nounset) | Referencing an unset variable is fatal |
46-
| `set -o pipefail` | A pipeline fails if any command in it fails |
47-
| `IFS=''` | Word splitting is disabled by default |
48-
| `shopt -s inherit_errexit` | Command substitutions inherit errexit |
49-
| `set -o errtrace` | ERR traps propagate into functions and subshells |
38+
| Setting | Effect |
39+
|--------------------------|-----------------------------------------------------|
40+
| `set -e` (errexit) | Non-zero return terminates unless caught |
41+
| `set -u` (nounset) | Referencing an unset variable is fatal |
42+
| `set -o pipefail` | A pipeline fails if any command in it fails |
43+
| `IFS=''` | Word splitting is disabled by default |
44+
| `shopt -s inherit_errexit` | Command substitutions inherit errexit |
45+
| `set -o errtrace` | ERR traps propagate into functions and subshells |
5046

5147
**The `IFS=''` default is important.** Unquoted `$var` where
5248
`var="a b c"` stays as a single string, not three words. Use
@@ -56,13 +52,13 @@ opsh sets these options before your script runs. Do not disable them.
5652

5753
These are set by opsh before your script runs:
5854

59-
| Variable | Description |
60-
| -------------- | ------------------------------------------- |
61-
| `$SCRIPTFILE` | Absolute path to your script |
62-
| `$SCRIPTDIR` | Directory containing your script |
63-
| `$TMPDIR` | Managed temp directory, cleaned up on exit |
64-
| `$OPSHROOTDIR` | Root of the opsh installation |
65-
| `$DEBUG` | Set this (any value) to enable `log::debug` |
55+
| Variable | Description |
56+
|---------------|------------------------------------------------|
57+
| `$SCRIPTFILE` | Absolute path to your script |
58+
| `$SCRIPTDIR` | Directory containing your script |
59+
| `$TMPDIR` | Managed temp directory, cleaned up on exit |
60+
| `$OPSHROOTDIR`| Root of the opsh installation |
61+
| `$DEBUG` | Set this (any value) to enable `log::debug` |
6662

6763
Color variables `$CRED`, `$CGRN`, `$CYEL`, `$CBLU`, `$CNONE` are
6864
available and are automatically empty when output is not a terminal.
@@ -97,13 +93,13 @@ deploy::cleanup() { ... }
9793
All log output goes to stderr. Messages are colorized when stderr is a
9894
terminal.
9995
100-
| Function | Behavior |
101-
| ------------ | -------------------------------------- |
102-
| `log::debug` | Blue output, only when `$DEBUG` is set |
103-
| `log::info` | Green output |
104-
| `log::warn` | Yellow output |
105-
| `log::error` | Red output |
106-
| `log::fatal` | Red output, then `exit 1` |
96+
| Function | Behavior |
97+
|----------------|---------------------------------------------|
98+
| `log::debug` | Blue output, only when `$DEBUG` is set |
99+
| `log::info` | Green output |
100+
| `log::warn` | Yellow output |
101+
| `log::error` | Red output |
102+
| `log::fatal` | Red output, then `exit 1` |
107103
108104
```bash
109105
log::info "deploying version $VERSION..."
@@ -179,7 +175,7 @@ lib::import command
179175
```
180176
181177
| Function | Description |
182-
| ----------------- | ---------------------------------- |
178+
|-------------------|------------------------------------|
183179
| `command::exists` | Returns 0 if command is in `$PATH` |
184180
185181
```bash
@@ -192,10 +188,10 @@ command::exists docker || log::fatal "docker is required"
192188
lib::import path
193189
```
194190
195-
| Function | Description |
196-
| ------------------- | ------------------------------- |
197-
| `path::env::add` | Prepend directories to `$PATH` |
198-
| `path::env::remove` | Remove a directory from `$PATH` |
191+
| Function | Description |
192+
|---------------------|--------------------------------------|
193+
| `path::env::add` | Prepend directories to `$PATH` |
194+
| `path::env::remove` | Remove a directory from `$PATH` |
199195
200196
```bash
201197
path::env::add /opt/mytools/bin
@@ -208,13 +204,13 @@ path::env::remove /usr/local/old/bin
208204
lib::import git
209205
```
210206
211-
| Function | Description |
212-
| --------------------------- | ------------------------------------------------------- |
213-
| `git::repo::version` | Version from `git describe --tags --dirty` or short SHA |
214-
| `git::repo::current-branch` | Current branch name |
215-
| `git::repo::is-clean` | Returns 0 if working tree is clean |
216-
| `git::tag::exists` | Returns 0 if a local tag exists |
217-
| `git::tag::lookup::remote` | Lookup a tag on a remote; prints commit hash |
207+
| Function | Description |
208+
|-------------------------------|----------------------------------------------------------|
209+
| `git::repo::version` | Version from `git describe --tags --dirty` or short SHA |
210+
| `git::repo::current-branch` | Current branch name |
211+
| `git::repo::is-clean` | Returns 0 if working tree is clean |
212+
| `git::tag::exists` | Returns 0 if a local tag exists |
213+
| `git::tag::lookup::remote` | Lookup a tag on a remote; prints commit hash |
218214
219215
`git::tag::lookup::remote` returns 1 if the tag is not found, 2 if
220216
ambiguous.
@@ -231,7 +227,7 @@ lib::import semver
231227
```
232228
233229
| Function | Description |
234-
| --------------- | ------------------------------------------------------- |
230+
|-----------------|---------------------------------------------------------|
235231
| `semver::parse` | Parse into `$OPSH_SEMVER` array `[major, minor, patch]` |
236232
| `semver::test` | Compare two versions: `-eq`, `-gt`, `-lt`, `-ge`, `-le` |
237233
| `semver::bump` | Bump `major`, `minor`, or `patch`; prints new version |
@@ -255,14 +251,14 @@ new=$(semver::bump minor v1.2.3) # v1.3.0
255251
lib::import ssh
256252
```
257253
258-
| Function | Description |
259-
| ------------------------ | --------------------------------------------- |
260-
| `ssh::begin` | Start SSH context: agent, proxied ssh, config |
261-
| `ssh::end` | Tear down SSH context |
262-
| `ssh::config` | Append SSH config from stdin |
263-
| `ssh::key::add` | Add keys from files or stdin to the agent |
264-
| `ssh::background::run` | Launch SSH port forwarding in background |
265-
| `ssh::background::close` | Close background port forwarding |
254+
| Function | Description |
255+
|--------------------------|------------------------------------------------|
256+
| `ssh::begin` | Start SSH context: agent, proxied ssh, config |
257+
| `ssh::end` | Tear down SSH context |
258+
| `ssh::config` | Append SSH config from stdin |
259+
| `ssh::key::add` | Add keys from files or stdin to the agent |
260+
| `ssh::background::run` | Launch SSH port forwarding in background |
261+
| `ssh::background::close` | Close background port forwarding |
266262
267263
`ssh::begin` creates an isolated SSH agent, a proxied `ssh` binary
268264
that uses a managed config file, and registers `ssh::end` as an exit
@@ -287,10 +283,10 @@ ssh::end
287283
lib::import cloud-init
288284
```
289285
290-
| Function | Description |
291-
| ----------------------------- | ---------------------------------- |
292-
| `cloud-init::is-enabled` | Returns 0 if cloud-init is present |
293-
| `cloud-init::wait-for-finish` | Blocks until cloud-init completes |
286+
| Function | Description |
287+
|--------------------------------|-------------------------------------|
288+
| `cloud-init::is-enabled` | Returns 0 if cloud-init is present |
289+
| `cloud-init::wait-for-finish` | Blocks until cloud-init completes |
294290
295291
```bash
296292
if cloud-init::is-enabled; then
@@ -305,9 +301,9 @@ fi
305301
lib::import step-runner
306302
```
307303
308-
| Function | Description |
309-
| ------------ | --------------------------------------------------- |
310-
| `steps::run` | Run all `prefix::*` functions in alphabetical order |
304+
| Function | Description |
305+
|---------------|-------------------------------------------------------|
306+
| `steps::run` | Run all `prefix::*` functions in alphabetical order |
311307
312308
Define functions with a shared prefix, then run them:
313309
@@ -329,11 +325,11 @@ control ordering.
329325
lib::import test-harness
330326
```
331327
332-
| Function | Description |
333-
| ------------------- | ------------------------------------------- |
334-
| `testing::register` | Register a test function with a description |
335-
| `testing::run` | Execute all tests, output TAP v13 |
336-
| `testing::fail` | Fail the current test with a message |
328+
| Function | Description |
329+
|----------------------|------------------------------------------|
330+
| `testing::register` | Register a test function with a description |
331+
| `testing::run` | Execute all tests, output TAP v13 |
332+
| `testing::fail` | Fail the current test with a message |
337333
338334
See the "Writing Tests" section below.
339335

tests/unit/corbits-skills-catalog.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,23 @@ test("implement skill is 1:1 with GaaS implement", async () => {
149149
expect(skill).not.toContain("Do not invent a worker-count");
150150
});
151151

152+
test("opsh skill is 1:1 with GaaS opsh", async () => {
153+
const skill = await Bun.file(join(pluginRoot, "skills/opsh/SKILL.md")).text();
154+
expect(skill).toContain(USER_INVOCABLE_FALSE);
155+
expect(skill).not.toContain(DISABLE_MODEL_INVOCATION);
156+
expect(skill).toContain("# opsh Scripting");
157+
expect(skill).toContain("#!/usr/bin/env opsh");
158+
expect(skill).toContain("lib::import");
159+
expect(skill).toContain("TAP v13");
160+
expect(skill).toContain("prove");
161+
expect(skill).toContain("testing::register");
162+
expect(skill).toContain("Load this skill when writing, reviewing, or debugging opsh scripts.");
163+
expect(skill).not.toContain("spawn_agent");
164+
expect(skill).not.toContain("write_file/edit_file");
165+
expect(skill).not.toContain("Tiny / single-file scripts");
166+
expect(skill).not.toContain("## Acknowledgment");
167+
});
168+
152169
test("first-party skills are how-to playbooks, not director personas", async () => {
153170
const gaasOverlap = new Set([
154171
"ast-grep",
@@ -373,6 +390,8 @@ test("native-integration maps GaaS tool names and parks Corbits extras", async (
373390
expect(skill).toContain("GIT_SEQUENCE_EDITOR");
374391
expect(skill).toContain("intern executes sequenced git via `run_shell`");
375392
expect(skill).toContain("Do not fork the GaaS git-rebase body");
393+
expect(skill).toContain("Do not fork the GaaS opsh body");
394+
expect(skill).toContain("prove");
376395
});
377396

378397
test("loadSkillCommands lists exactly the nine slash actions", async () => {

0 commit comments

Comments
 (0)