Turn a website's OpenAPI/Swagger JSON into a CLI.
Status: v0.1 (Crystal). The core implemented pieces are:
.well-known/wacli.jsonmanifest parsing and fetching- OpenAPI JSON detection (Swagger 2.0, OpenAPI 3.0, OpenAPI 3.1)
- Operation routing by path tokens
wacli oas validateinternal compatibility check
-
Install Crystal (1.8+) and
shardson your platform. -
Install dependencies and run tests:
shards install
crystal spec- Build:
shards build --releaseThe binary will be at bin/wacli.
Packaging assets and scripts live in .meta/packaging.
Release artifacts are built with:
- Native Crystal builds in GitHub Actions (no
misein CI) - Tarballs named
wacli-<version>-<os>-<arch>-<link_mode>.tar.gz dist/SHA256SUMSchecksum file- Homebrew formula generated at
.meta/packaging/homebrew/wacli.rb - Container image published to
ghcr.io/<owner>/wacli
Lua release download helper:
.meta/packaging/mise/download.lua
wacli oas validate <file_or_url>Exit codes:
0: compatible (parseable + haspaths)2: valid JSON but unsupported OpenAPI version3: invalid JSON or missing required OpenAPI fields (for v0.1: missing/invalidpaths)
Downloads a tool manifest, then downloads its OpenAPI JSON and caches it (and records it in the lock file).
wacli ain <tool_ref>wacli help <tool_ref>wacli auth <tool_ref> --bearer TOKENTokens are stored in a sqlite DB (db_path from config).
The token is applied in both modes:
- manifest mode (
.well-known/wacli.json) - fallback mode (
/openapi.jsonor/swagger.json)
wacli <tool_ref> [method] <path_tokens...> [key=value...] [--json STR] [--header k:v] [--render MODE] [--out PATH] [--interactive|--no-interactive] [--dry-run]Notes:
methodis optional; defaults toGET.path_tokensare matched against an OpenAPI path template. Example template/repos/{owner}/{repo}/issuesmatches tokensrepos alice demo issues.key=valueargs become query parameters.--jsonsets the request body and defaultsContent-Typetoapplication/jsonif not already specified in headers.--json @file.jsonreads request JSON from a file.--render auto|table|json|rawformats JSON output (default:auto).--out PATHsaves the response to a file (use--out -to force raw bytes to stdout).- For
POST/PUT/PATCHwithout--json,wacliprompts interactively when stdin is a TTY (disable with--no-interactive). --dry-runprints the resolved request instead of sending it.
cat response.json | wacli render --render table
wacli render --in response.json --render jsonTo call tools directly from your shell without typing wacli each time, generate aliases:
eval "$(wacli shell bash example.org)"
example.org get ping --dry-runFor all locally installed/cached tools (from wa.lock):
eval "$(wacli shell bash --installed)"tool_ref forms:
example.com(assumeshttps://example.com)https://example.com(explicit)registry:<name>(resolved using configuri_schemes.registry)
Your website should host:
https://<host>/.well-known/wacli.json
For backward compatibility, wacli also tries:
https://<host>/.well-know/wacli.json(deprecated)
Fallback (when no manifest exists):
https://<host>/openapi.jsonhttps://<host>/swagger.json
In fallback mode, wacli treats the OpenAPI JSON as the tool spec (no headers/aliases/auth from a manifest).
When you run wacli <tool_ref> ..., the resolution order is:
- Local tool manifest override:
$XDG_CONFIG_HOME/wacli/tools/<tool>.json(for aliases/headers/auth) - Local cached OpenAPI JSON from
wacli ain <tool_ref>(for the OpenAPI spec) - Remote manifest:
https://<host>/.well-known/wacli.json(then/.well-know/wacli.json) - Remote fallback:
https://<host>/openapi.jsonthenhttps://<host>/swagger.json
You can define local per-tool aliases/headers/auth by creating a local manifest override:
$XDG_CONFIG_HOME/wacli/tools/<tool>.json(default:$HOME/.config/wacli/tools/<tool>.json)
Where <tool> is derived from the tool reference (for example example.org.json).
This file has the same schema as .well-known/wacli.json (tool manifest).
You can also pass a manifest file path directly as <tool_ref>:
wacli help example.org Minimal:
{
"api": "https://example.com/openapi.json"
}Full (v0.1 fields):
{
"api": "https://example.com/openapi.json",
"settings": {
"headers": [
{ "name": "Accept", "value": "application/json" }
],
"aliases": [
{
"alias": "issues",
"type": "path",
"content": "/repos/{owner}/{repo}/issues"
}
],
"auth": {
"scheme": "bearer",
"tokenName": "Authorization"
}
}
}Alias behavior (v0.1):
type: "path"aliases replace a matching token withcontentsplit by/.- Placeholder segments like
{owner}will consume subsequent CLI tokens as values.
Auth behavior (v0.1):
- Only
beareris implemented. tokenNameis treated as the header name. If it is"Authorization", the header value becomesBearer <token>. Otherwise the token is sent as-is.
A registry is also served from .well-known/wacli.json but sets registry: true and a manifests map:
{
"registry": true,
"manifests": {
"forgejo": { "path": "https://wacli.ofs.lol/registry/forgejo.json" }
}
}When tool_ref is registry:forgejo, wacli:
- Loads the registry base URL from config
uri_schemes.registry - Fetches the registry manifest from its
.well-known/wacli.json - Fetches
manifests.forgejo.pathas the tool manifest
Accepted versions:
- Swagger 2.0 (
"swagger": "2.x") - OpenAPI 3.0 (
"openapi": "3.0.x") - OpenAPI 3.1 (
"openapi": "3.1.x")
Routing:
- The selected operation is matched by
method+ path template segment match. - Template segments like
{id}match any token and are extracted as path parameters.
Base URL:
- Swagger 2.0:
schemes[0]://host + basePath(falls back totool_refbase if missing) - OpenAPI 3.x:
servers[0].url(falls back totool_refbase if missing)
Path:
$XDG_CONFIG_HOME/wacli/wacfg.json(default:$HOME/.config/wacli/wacfg.json)
Example:
{
"db_path": "$HOME/.cache/wacrd.db",
"install_dir": "$HOME/.local/bin",
"uri_schemes": {
"registry": "https://wareg.re128.org"
}
}Path:
$XDG_CONFIG_HOME/wacli/wa.lock
v0.1 writes ains entries when you run wacli ain <tool_ref>.
See:
examples/re128.org/.well-known/wacli.jsonexamples/wareg.re128.org/.well-known/wacli.jsonexamples/settings.json
This repo includes a skill for using wacli against platform APIs (discovery, dry-run, auth, troubleshooting):
skills/wacli/SKILL.md
To install it into Codex:
mkdir -p ~/.codex/skills
ln -s "$(pwd)/skills/wacli" ~/.codex/skills/wacliSkill metadata name is wacli (file stays in that folder).