Routines

Routines are named workflows that run multiple cli4ai commands (and optionally other executables) in sequence. Use them to make “run these 4 commands” repeatable, parameterized, and easy for agents to execute.

Quick Start

# Run a routine (local-first)
cli4ai routines run daily-report --var lang=rust

# Use global routines only
cli4ai routines run daily-report --global

# Debug without running
cli4ai routines run daily-report --dry-run --var lang=rust

Where routines live

Routines are stored as files, either local to a project or globally in your home directory:

# Local (project-specific)
./.cli4ai/routines/
  daily-report.routine.json
  daily-report.routine.sh

# Global (personal)
~/.cli4ai/routines/
  daily-report.routine.json
  daily-report.routine.sh

Resolution is local-first by default:

# Resolution order (default)
1) ./.cli4ai/routines/.routine.json
2) ./.cli4ai/routines/.routine.sh
3) ~/.cli4ai/routines/.routine.json
4) ~/.cli4ai/routines/.routine.sh

# With --global
1) ~/.cli4ai/routines/.routine.json
2) ~/.cli4ai/routines/.routine.sh

Managing routines

# List routines (local + global)
cli4ai routines list

# Create routines
cli4ai routines create daily-report --type json
cli4ai routines create scratchpad --type bash --global

# Edit/view/remove
cli4ai routines edit daily-report
cli4ai routines show daily-report
cli4ai routines remove daily-report

# Run
cli4ai routines run daily-report --var lang=rust

Two routine types

1) Script routines (.routine.sh)

Script routines are the fastest way to get started. They run via bash. Any --var KEY=value flags are exposed as environment variables like CLI4AI_VAR_KEY.

  • Args: any extra arguments after the routine name are passed through to the script.
  • Output: in a TTY, stdio is inherited; in non‑TTY, stdout/stderr are captured and returned as one JSON summary.
#!/usr/bin/env bash
set -euo pipefail

# Vars passed via --var KEY=value are available as env vars:
#   CLI4AI_VAR_LANG=rust
# Routine metadata is also exposed:
#   CLI4AI_ROUTINE_NAME=daily-report
#   CLI4AI_ROUTINE_PATH=/absolute/path/to/daily-report.routine.sh

lang="${CLI4AI_VAR_LANG:-rust}"

# Chain cli4ai commands
cli4ai run github trending "$lang"

# Example of using other tools
git status --porcelain 1>&2

2) Structured routines (.routine.json)

Structured routines are designed for orchestration: each step can capture stdout, parse JSON, and pass data to later steps via templates.

Note: extra positional args after the routine name are currently only passed to script routines; structured routines use --var.

{
  "version": 1,
  "name": "daily-report",
  "description": "Example: chain cli4ai + exec steps",
  "vars": {
    "lang": { "default": "rust" },
    "channel": { "default": "claude" }
  },
  "steps": [
    {
      "id": "trending",
      "type": "cli4ai",
      "package": "github",
      "command": "trending",
      "args": ["{{vars.lang}}"],
      "capture": "json"
    },
    {
      "id": "pickRepo",
      "type": "set",
      "vars": {
        "repo": "{{steps.trending.json.0.fullName}}"
      }
    },
    {
      "id": "issues",
      "type": "cli4ai",
      "package": "github",
      "command": "issues",
      "args": ["{{vars.repo}}"],
      "capture": "json"
    },
    {
      "id": "post",
      "type": "cli4ai",
      "package": "slack",
      "command": "post",
      "args": [
        "{{vars.channel}}",
        "Top repo: {{vars.repo}}"
      ],
      "capture": "json"
    }
  ],
  "result": {
    "repo": "{{vars.repo}}",
    "issues": "{{steps.issues.json}}",
    "slack": "{{steps.post.json}}"
  }
}

Execution model (structured routines)

┌────────────────────────────────────────────────────────────┐
│ cli4ai routines run daily-report --var lang=rust              │
└────────────────────────────────────────────────────────────┘
  1) Resolve file (.cli4ai/routines → ~/.cli4ai/routines)
  2) Parse + validate JSON schema (version 1, unique step ids)
  3) Init context
     - vars = defaults + --var overrides
     - steps = {}
  4) Execute steps in order
     a) Render templates against { vars, steps }
     b) Run step
        - type: cli4ai  → runs a cli4ai tool (same resolver + secrets injection as cli4ai run)
        - type: exec  → spawn(cmd, args, shell:false) (captures stdout/stderr)
        - type: set   → assigns vars from rendered templates
     c) Save result to steps. for later templates
     d) Stop on non-zero exit unless continueOnError=true
  5) Emit final output
     - stdout: single JSON summary
     - stderr: streamed progress/stderr from steps

Templating

Templates reference vars and prior steps. Missing paths are hard errors during an actual run. --dry-run is lenient and leaves unresolved {{...}} placeholders intact.

# Vars
{{vars.lang}}

# Step stdout/stderr
{{steps.trending.stdout}}
{{steps.trending.stderr}}

# Step JSON (capture: "json")
{{steps.trending.json}}
{{steps.trending.json.0.fullName}}

Output

Structured routine runs emit a single JSON summary on stdout. Step stderr is streamed to stderr so agents can ignore it.

{
  "kind": "json",
  "scope": "local",
  "path": "/path/to/.cli4ai/routines/daily-report.routine.json",
  "routine": "daily-report",
  "version": 1,
  "status": "success",
  "exitCode": 0,
  "durationMs": 1234,
  "vars": { "lang": "rust", "repo": "owner/name" },
  "steps": [
    { "id": "trending", "type": "cli4ai", "status": "success", "exitCode": 0, "json": [/* ... */] }
  ],
  "result": { "repo": "owner/name" }
}

Examples

Ready-to-use routines you can copy and customize. See the Examples section for complete walkthroughs.

Notes

  • Local by default: routines are usually project-specific; use --global for personal utilities.
  • No composition (v1): if you want nesting, use a bash routine that calls cli4ai routines run.
  • Exec safety: exec steps spawn with shell: false; use bash -lc if you need shell features.
  • AI integration: pipe data to claude --print, llm, or any CLI tool for AI-powered processing.