# X Cmd Action

> Author GitHub Actions workflows that use x-cmd/action — the portable-action pattern for shell-first CI. Use when the user asks to write, fix, or review a GitHub Actions workflow that should run x-cmd commands or be portable between local and CI.

- Skill: `x-cmd/x-cmd-action` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add x-cmd/x-cmd-action`
- Raw SKILL.md: https://api.skillmd.com/api/skills/x-cmd/x-cmd-action/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: x-cmd (https://skillmd.com/u/x-cmd)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/x-cmd/x-cmd-action

---


# x-cmd/action — Skill

[中文 README](./README.cn.md) · [English README](./README.md)

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:

1. **Installs x-cmd** into `~/.x-cmd.root/`.
2. **Runs a shell script** (provided as `script:`, `code:`, or a convention file).
3. **Uploads an artifact** from `~/ws/.artifact` via `actions/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

```yaml
- uses: x-cmd/action@main
  with:
    code: x cowsay "hello"
```

### 4.2 Portable script (preferred)

`scripts/ci.sh`:

```bash
#!/usr/bin/env bash
. "$HOME/.x-cmd.root/X"

x sysinfo | head
x ws build
```

`workflow.yml`:

```yaml
- 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:

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: x-cmd/action@main
        # No `script:` — defaults to .x-cmd/build
```

`.x-cmd/build`:

```bash
. "$HOME/.x-cmd.root/X"
x ws build
```

### 4.4 Git push (ssh-agent + key + git identity)

```yaml
- 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

```yaml
- 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

```yaml
- 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

```yaml
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:

```yaml
- 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

```yaml
- 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/checkout` before `x-cmd/action`** — only needed if your script needs the current repo's files. The action pulls its own dispatcher via `curl` and only clones `ws_owner_repo` if you ask.
- ❌ **Adding `actions/setup-node` / `setup-python` / `setup-go`** — x-cmd provides `x env use node`, `x env use python`, `x env use go`. Prefer those.
- ❌ **Putting secrets in `code:`** — pass via `env:` and reference as `$VAR` in `code:`. The action's dedicated inputs (`ssh_key`, `docker_password`, etc.) are the proper channels.
- ❌ **Relying on `x` being on PATH without loading** — first line of any portable script is `. "$HOME/.x-cmd.root/X"`. The `X` file is idempotent.
- ❌ **Expecting `jq` / `node` / etc. on PATH after `x eget use` without loading x-cmd** — `x eget use` drops the binary into `$HOME/.local/bin/`, and `x env use` lands it under `~/.x-cmd.root/local/data/pkg/sphere/.../bin/`. Neither path is on `PATH` by default. Sourcing `X` adds them; otherwise `export PATH="$HOME/.local/bin:$PATH"` manually. See FAQ in README.
- ❌ **Hard-coding `~/ws/.artifact`** in the script — write the script to honor `$ARTIFACT_PATH` if 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/checkout` unless 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 in `code:`.
- [ ] If pushing back to GitHub: `ssh_key` + `git_user` + `git_email` are all set.
- [ ] If uploading artifacts: verify `artifact_path` actually exists after `code:` 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, `@main` only for dev.

---

## 8. Template outputs

### 8.1 Build + test + publish (single job)

```yaml
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

```yaml
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

```yaml
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` (under `x-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:

1. Check the **init step logs** — they show `HOME[...]` and the curl output. If x-cmd install failed, the rest will too.
2. Check that the script runs locally first (`./scripts/ci.sh`).
3. Verify the workspace repo + ref are reachable if `ws_owner_repo` is set.
4. Confirm secrets are present at the job level if not set per-step.
5. Look at the action's [README FAQ](./README.md#5-faq) for the specific failure mode.

