Skip to main content

Headless CLI and CI

The Achilles desktop is interactive, but the Achilles binary also runs fully headless. Everything the desktop does over scans and findings has a headless form, which makes Achilles a drop-in CI step or scheduled job.

Scan and query

achilles appsec scan --path examples/achilles-scan-fixture
achilles appsec query --path examples/achilles-scan-fixture
  • scan walks the tree, runs the engines, and writes results to the local ledger.
  • query reads the ledger back out: findings, triage states, and run history.
  • The default quick mode walks the full tree. Add --mode diff to limit secrets, SAST, and surfaces checks to git-changed files (SCA still reads lockfiles regardless of mode).

Both commands work against the synthetic example trees shipped in the repo, examples/achilles-scan-fixture/ and examples/achilles-fixtures/, whose values are documentation-shaped, never real credentials.

Investigate and brief

The remaining appsec subcommands mirror the MCP tools:

CommandBehavior
achilles appsec scanRun engines and persist findings
achilles appsec queryRead findings and triage states from the ledger
achilles appsec investigateRun the investigator/validator loop over selected ledger ids
achilles appsec briefProduce a fix brief for one or more findings
achilles appsec verdictRecord a triage outcome (confirmed, false positive, fixed)
achilles appsec triageWork the open triage queue

Findings land in the same local SQLite ledger (achilles.db) no matter which surface wrote them, which is what keeps scheduled CI runs consistent with the decisions you made in the desktop app.

Recipes from the CLI

Run a shipped or imported recipe by name (names resolve after the app has materialized shipped recipes once) or by path:

achilles run --recipe scan-recap --params workspace=/path/to/repo
achilles run --recipe recipes/security-review.yaml --params workspace=/path/to/repo --params pr=123

Scheduled jobs

Start the server with --enable-scheduler to fire recipes on cron:

# Daily 02:00 local - fast scan plus recap
achilles schedule add --schedule-id nightly-scan --cron "0 0 2 * * *" \
--recipe-source recipes/scan-recap.yaml \
--params workspace=/path/to/repo

# Monday 09:00 local - SCA plus pinning
achilles schedule add --schedule-id weekly-sca --cron "0 0 9 * * 1" \
--recipe-source recipes/sca-hygiene-report.yaml \
--params workspace=/path/to/repo

Always pass workspace explicitly so the job scans your target repository instead of the server's current directory.

CI pipeline example

A GitHub Actions step that scans the repo on every push and opens findings only when they are new:

- name: Achilles AppSec scan
run: |
achilles appsec scan --path ${{ github.workspace }}
achilles appsec query --path ${{ github.workspace }}

Because scans are ledger- and handle-aware, a finding a developer dismissed in the desktop does not come back as "new" on the next CI run; state lives in the ledger, not in the pipeline.

Diagnostics

When something misbehaves headless, produce a diagnostics bundle from the session id:

achilles session diagnostics --session-id <session_id>

The bundle includes OS, app version, enabled extensions, provider/model, and recent logs. Attach it when reporting a bug to kineticquant/achilles-harness issues (see building and troubleshooting).

Model keys for CLI-only machines

If the OS keyring you normally use on the desktop is absent in CI, configure provider keys as environment variables instead (OPENAI_API_KEY, ANTHROPIC_API_KEY, and so on), and use the app's config-root environment variable to isolate config between environments. Fast mode is extremely token-efficient.