x-cmd/action — Skill
This skill teaches an agent how to author GitHub Actions workflows that use x-cmd/action. For background reading (full input tables, internal mechanics, FAQ) see the README; this file is the operating manual.
1. When to invoke
Trigger this skill when the user asks to:
- Write a new GitHub Actions workflow that runs
x ...commands. - Replace an existing
actions/checkout+actions/setup-*chain with a portable shell script. - Add a CI step that pushes back to GitHub, builds a Docker image, or uploads artifacts.
- Review or fix an existing workflow that uses (or should use)
x-cmd/action.
Do not invoke if the user is on a non-GitHub CI provider — x-cmd/action is GitHub-specific. For other CI, point them to x-cmd's generic install pattern (README §A).
2. Core thesis (memorize this)
x-cmd/action does exactly three things:
- Installs x-cmd into
~/.x-cmd.root/. - Runs a shell script (provided as
script:,code:, or a convention file). - Uploads an artifact from
~/ws/.artifactviaactions/upload-artifact@v4.
Everything else is the user's responsibility — by design. The action's job is infrastructure friction (ssh-agent, docker login, git identity). Toolchain friction (node, python, rust) is x-cmd's job: x env use node, x npm, etc.
Therefore: the workflow's job is to write a plain POSIX shell script. Do not reach for actions/checkout or actions/setup-* unless absolutely necessary. The script should be runnable locally with ./scripts/ci.sh and inside GitHub Actions with no changes.
3. Decision tree — which input to use
"How should the user provide the script body?"
│
├─ Single short command, throwaway, tied to this workflow only
│ └─→ with: { code: "x cowsay ..." }
│
├─ Sequence of commands, but still throwaway
│ └─→ with: { code: |
│ x sysinfo
│ x ws build
│ }
│
├─ Script that will grow, or one the user will also run locally
│ └─→ write scripts/ci.sh with . "$HOME/.x-cmd.root/X" at the top
│ with: { script: scripts/ci.sh }
│ (Or rely on convention: job name "build" → .x-cmd/build auto-loaded.)
│
└─ Steps that are conceptually unrelated
└─→ repeat the action, one `with: { code: ... }` per step
Default to portable script unless the user explicitly wants inline. Ask only if the choice is unclear from context.
4. Recipes
4.1 Minimal — single command
- uses: x-cmd/action@main
with:
code: x cowsay "hello"
4.2 Portable script (preferred)
scripts/ci.sh:
#!/usr/bin/env bash
. "$HOME/.x-cmd.root/X"
x sysinfo | head
x ws build
workflow.yml:
- uses: x-cmd/action@main
with:
script: scripts/ci.sh
The script must be runnable locally without changes. If the user has x-cmd installed (eval "$(curl -s https://get.x-cmd.com)" once), . "$HOME/.x-cmd.root/X" works there too.
4.3 Convention file
If the user doesn't want a separate script and is OK with a .x-cmd/<job-name> convention file:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: x-cmd/action@main
# No `script:` — defaults to .x-cmd/build
.x-cmd/build:
. "$HOME/.x-cmd.root/X"
x ws build
4.4 Git push (ssh-agent + key + git identity)
- uses: x-cmd/action@main
env:
ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
with:
git_user: ci-bot
git_email: ci@example.com
code: |
git clone git@github.com:me/repo.git
cd repo
echo updated >> README.md
git commit -am "ci"
git push
known_hosts is preloaded from x-cmd/knownhost — no manual github.com ssh-rsa line.
4.5 Clone a workspace repo
- uses: x-cmd/action@main
env:
ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
with:
ws_owner_repo: owner/ws
ws_repo_ref: main
script: .x-cmd/build
The clone becomes the ws/ symlink; the script's working directory is ws/. Use this when the build logic lives in a separate repo from the workflow.
4.6 Docker
- uses: x-cmd/action@main
with:
docker_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_password: ${{ secrets.DOCKERHUB_TOKEN }}
docker_buildx_init: 'true'
code: docker buildx build --platform linux/amd64,linux/arm64 -t me/app .
4.7 Matrix across containers
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
image: [xcmd/ubuntu-dev, xcmd/centos-dev]
container:
image: ${{ matrix.image }}
steps:
- uses: x-cmd/action@main
with:
code: x ws build ${{ matrix.image }}
4.8 Artifact upload
Anything under ~/ws/.artifact is uploaded automatically:
- uses: x-cmd/action@main
with:
code: x ws art # populates ~/ws/.artifact
artifact_name: release
artifact_path: ~/ws/.artifact
artifact_retention_days: 30
4.9 Switch x-cmd stream
- uses: x-cmd/action@main
env:
___X_CMD_GHACTION_X: x7 # x0 (community-dev) / x1-x6 (experimental) / x7 (alpha)
with:
code: x --version
5. Input reference (compact)
| Input | Default | When to set |
|---|---|---|
prehook |
— | Shell before main script |
script |
.x-cmd/<job-name> |
Path to a script file |
code |
— | Inline shell code |
posthook |
— | Shell after main script |
ws_owner_repo |
github.repository |
Clone a workspace repo |
ws_repo_ref |
github.head_ref || github.ref_name |
Branch/tag/SHA |
github_token |
secrets.GITHUB_TOKEN |
Authenticated HTTPS clone |
ssh_key |
— | SSH private key (PEM) |
git_user |
head-commit author | git config user.name |
git_email |
head-commit author email | git config user.email |
docker_username |
— | docker login user |
docker_password |
— | docker login password |
docker_buildx_init |
false |
docker buildx create --use |
artifact_name |
artifact |
Upload name |
artifact_path |
~/ws/.artifact |
Upload path |
artifact_not_found |
ignore |
warn / error / ignore |
artifact_retention_days |
10 |
1–90 |
Execution order when multiple are set: prehook → script → code → posthook.
6. Anti-patterns (do NOT do these)
- ❌ Adding
actions/checkoutbeforex-cmd/action— only needed if your script needs the current repo's files. The action pulls its own dispatcher viacurland only clonesws_owner_repoif you ask. - ❌ Adding
actions/setup-node/setup-python/setup-go— x-cmd providesx env use node,x env use python,x env use go. Prefer those. - ❌ Putting secrets in
code:— pass viaenv:and reference as$VARincode:. The action's dedicated inputs (ssh_key,docker_password, etc.) are the proper channels. - ❌ Relying on
xbeing on PATH without loading — first line of any portable script is. "$HOME/.x-cmd.root/X". TheXfile is idempotent. - ❌ Expecting
jq/node/ etc. on PATH afterx eget usewithout loading x-cmd —x eget usedrops the binary into$HOME/.local/bin/, andx env uselands it under~/.x-cmd.root/local/data/pkg/sphere/.../bin/. Neither path is onPATHby default. SourcingXadds them; otherwiseexport PATH="$HOME/.local/bin:$PATH"manually. See FAQ in README. - ❌ Hard-coding
~/ws/.artifactin the script — write the script to honor$ARTIFACT_PATHif you make it configurable; otherwise rely on the default. - ❌ Writing a workflow that only works on GitHub — if the script needs
${{ github.* }}interpolations, it's not portable. Hoist those into env vars and read with${VAR:-}. - ❌ Wrapping the action in
run: |blocks for "extra safety" —with: { code: | ... }already supports multi-line strings.
7. Verification checklist
Before declaring a workflow done:
- The script body runs locally with
./scripts/ci.sh(assuming x-cmd is installed). - No
actions/checkoutunless the script genuinely needs repo files. - No
actions/setup-*unless x-cmd doesn't cover that toolchain (rare). - Secrets go through
env:+ dedicated inputs, never literal incode:. - If pushing back to GitHub:
ssh_key+git_user+git_emailare all set. - If uploading artifacts: verify
artifact_pathactually exists aftercode:runs. - Matrix jobs use job-level
env:for shared inputs (the action falls back to env vars). - Pinned action version (e.g.
@v1.2.3) for production,@mainonly for dev.
8. Template outputs
8.1 Build + test + publish (single job)
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
env:
ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
git_user: ci-bot
git_email: ci@example.com
steps:
- uses: x-cmd/action@main
with:
script: scripts/ci.sh
artifact_name: build-output
artifact_path: ~/ws/.artifact
8.2 Matrix across OS
name: Build
on: [push]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: x-cmd/action@main
with:
code: x ws build ${{ matrix.os }}
8.3 Container matrix
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
image: [xcmd/ubuntu-dev, xcmd/centos-dev]
container:
image: ${{ matrix.image }}
steps:
- uses: x-cmd/action@main
with:
code: x ws build ${{ matrix.image }}
9. Related skills
x-cmd-dev— broader x-cmd module authoring.repo(underx-cmd skill0) — sharing repos across agents to avoid duplicate downloads.verify— running workflows locally before pushing.
10. Failure recovery
If a workflow fails after following these recipes:
- Check the init step logs — they show
HOME[...]and the curl output. If x-cmd install failed, the rest will too. - Check that the script runs locally first (
./scripts/ci.sh). - Verify the workspace repo + ref are reachable if
ws_owner_repois set. - Confirm secrets are present at the job level if not set per-step.
- Look at the action's README FAQ for the specific failure mode.