Model traffic goes to the gateway you configure. kyacode wires eleven coding harnesses (Claude Code, Codex, opencode, Qwen Code and seven more) to OpenAI-compatible and Anthropic-compatible inference gateways. A gateway you host or place inside your perimeter can keep prompts, completions and spawn-time wiring inside that perimeter. Third-party gateways follow their own data-governance and billing terms. kyacode adds no metering or billing of its own.
A single cgo-free Go binary takes your gateway key (stored locally), installs in one line on macOS, Linux and Windows, and injects the wiring (environment variables and throwaway config files) at spawn time, so your real harness configuration is never touched. Data sovereignty is a property of the setup, not a policy promise.
- Requirements
- Installing the binary (one-liners, version pinning, updating, removing, verify)
- Quick start
- Commands
- Harness wiring (including 1M context with Claude Code)
- Storage and security boundaries
- Troubleshooting
- Fallback: fetch from the GitHub release
- Build from source
- Repository layout
- Provenance
- Acknowledgements
- Issues and security
- License
- One supported harness. A missing harness is auto-installed on first
launchwhere an official installer exists: claude uses its own install script, opencode uses its own install script on POSIX and npm on Windows, and the rest of the installable set installs vianpm install -g(so Node.js/npm must be onPATH); see Commands. - A valid KYA gateway key (issued with your gateway deployment).
One line per platform. POSIX shells (macOS, Linux):
curl -fsSL https://kyaky.ai/kyacode/install.sh | shWindows (PowerShell):
irm https://kyaky.ai/kyacode/install.ps1 | iexShipped builds: macOS and Linux in x86_64 and arm64; Windows in x86_64 only (the installer refuses Windows-on-ARM).
From cmd.exe, run: powershell -NoProfile -Command "irm https://kyaky.ai/kyacode/install.ps1 | iex".
Pasting the POSIX one-liner into Git Bash on Windows refuses by design and
prints the Windows command. Both URLs are the canonical script forms served
by the KYA inference host; there is no redirect layer to keep alive.
Every platform installs the same command: plain kyacode (kyacode.exe on
Windows). The binary lands in %LOCALAPPDATA%\Programs\kyacode on Windows
with the user PATH registered, and in ~/.local/bin on POSIX, with a
paste-ready export PATH=... hint printed if that directory is not on
PATH. The installer never elevates, never prompts, and never touches rc
files. The POSIX installer refuses to run as root (it installs into your own
home) and needs curl on PATH. Scripted installs: KYACODE_INSTALL_DIR
relocates the install directory on both platforms, and setting
KYACODE_SKIP_PATH_PERSIST skips the Windows user-PATH registration.
Pin a version with KYA_VERSION or a positional argument:
curl -fsSL https://kyaky.ai/kyacode/install.sh | KYA_VERSION=v0.1.0 sh
curl -fsSL https://kyaky.ai/kyacode/install.sh | sh -s v0.1.0(The intuitive KYA_VERSION=v0.1.0 curl ... | sh does nothing: the prefix
binds the variable to curl only, and sh never sees it.)
On Windows, the piped irm | iex run cannot take arguments, so pin that
form by setting KYA_VERSION in the environment first; a downloaded copy
of install.ps1 (saved to a file and run) also takes -Target vX.Y.Z.
Every install downloads the binary and its .sha256 sidecar, verifies
before replacing, and refuses, leaving the working binary intact, on any
download or checksum failure. The one failure where sh receives an empty
script and the pipeline still exits 0 with nothing installed is covered in
Troubleshooting.
Re-run the same one-liner: it overwrites the installed binary in place, and
the latest assets in the dist directory are always the newest build. A
pinned KYA_VERSION install is equally repeatable.
Run kyacode unauth to remove the stored key. Delete the binary
(~/.local/bin/kyacode on POSIX, %LOCALAPPDATA%\Programs\kyacode on
Windows, plus the user-PATH entry if you want it gone) and remove
~/.kyacode for the leftover config.json. A scripted install honours
KYACODE_INSTALL_DIR, so if you set it, delete the binary from that
directory instead of the defaults above. Per-launch sandboxes are
cleaned on exit and swept by kyacode status, so they need no action.
Either route, verify what you ended up running:
kyacode versionA tagged-release install prints its semver (stamped at build time); a build
from source prints v0.0.0-dev and says so.
Note
These commands assume kyacode is already on PATH; if it is not, start
with Installing the binary. If your key comes
from your own gateway deployment, run kyacode gateway <url> first: the
default base is the maintainer's own instance, and doctor would
otherwise send your key there.
kyacode auth # paste your gateway key (stored 0600 on unix)
kyacode doctor # pre-flight: five gateway probes
kyacode launch claude qwen3.8-27b-nvfp4The gateway key comes with your gateway deployment; kyacode itself does not issue keys.
Model ids are gateway-specific: run kyacode models to list yours. Note
that kyacode models lists every id the gateway serves, including
embedding, rerank and speech families no harness can chat with. Only the
codex catalog and the claude alias picker filter those out (a name
heuristic; the model you pass explicitly is never overridden); the other
catalog carriers list every served id, so pass a chat model id.
The default gateway base is the maintainer's own instance (https://kyaky.ai,
not a public service; it needs a key like any other). Point kyacode at any
OpenAI-compatible and Anthropic-compatible gateway with
kyacode gateway <url>, or print the current setting with bare
kyacode gateway.
Pointing kyacode at your own instance? The routes kyacode can use are:
POST /v1/messages (Anthropic shape), POST /v1/chat/completions and
POST /v1/responses (OpenAI shapes), and GET /v1/models returning an
OpenAI-style {"data":[{"id":...}]} list. kyacode doctor checks a
candidate base URL against all of them in one run. A base serving a subset
still runs the harnesses whose wiring needs only those routes (qwen, cline
and hermes speak one OpenAI route and fetch no catalog). Every call carries
the same key as a Bearer Authorization header, and a 3xx answer is
refused outright (a redirect hop would carry the key). A trailing /v1 on
a pasted URL is accepted and stripped; the stored form is canonically
without it.
| command | purpose |
|---|---|
kyacode auth |
store your gateway key (hidden prompt on a tty; --stdin forces the raw read; mode 0600 on unix) |
kyacode unauth |
remove the stored key |
kyacode gateway [url] |
show or set the gateway base URL (https:// required; see KYA_GATEWAY_INSECURE) |
kyacode doctor |
pre-flight: five probes (three entry protocols, a warning-level beta-header check, and the model listing) |
kyacode status |
key / gateway / harness overview; runs the orphan sweep |
kyacode models |
list gateway models (10s timeout) |
kyacode launch <harness> [model] [-- extra args...] |
spawn a harness against the gateway |
kyacode version |
print the build's version (tagged releases stamp semver) |
kyacode help |
usage (-h / --help) |
Extra args after -- are passed through verbatim to the harness:
kyacode launch claude <model> -- --continueBefore --, the first argument is taken as the model only when it does not
start with -; a leading flag sends all remaining pre--- arguments to
the harness as passthrough. The refusal applies only when a model argument
is present: any other extra argument before -- is refused, because
harness flags belong after --. The
single-model harnesses (see Harness wiring) refuse a
launch with no model at all:
<harness> requires a model: kyacode launch <harness> <model> [-- extra args...]
A missing harness is auto-installed through its official installer, after a
y/N confirmation, except hermes, openclaw and qwen, which you must
install yourself.
The eleven harnesses:
| name | product | install channel |
|---|---|---|
| claude | Anthropic Claude Code | official installer (claude.ai script / PowerShell) |
| opencode | opencode | official installer (curl on POSIX, npm on Windows) |
| codex | OpenAI Codex CLI | npm i -g @openai/codex |
| cline | Cline | npm i -g cline |
| droid | Droid (Factory) | npm i -g droid |
| dsh | DeepSeek Harness | npm i -g @deepseek-ai/dsh |
| omp | Oh My Pi | npm i -g oh-my-pi |
| pi | Pi coding agent | npm i -g @earendil-works/pi-coding-agent |
| qwen | Qwen Code CLI | manual (see the Qwen Code project) |
| hermes | Hermes (Nous Research) | manual (see the upstream project) |
| openclaw | OpenClaw | manual (see the upstream project) |
| exit | meaning |
|---|---|
0 |
the subcommand succeeded |
1 |
any failed subcommand: refused command shape (extra/unexpected arguments), key/gateway problems, redirect refusals, failed pre-flight, failed launch |
2 |
unknown subcommand or no subcommand at all (usage-shaped misuse) |
Integrations that only need success/failure can treat everything non-zero as
failure; 2 additionally tells you the invocation itself was malformed.
An interrupted launch also exits 1 once the escalation windows expire
(stderr banner interrupt: forcing exit, with no further error: line); a
child that finished cleanly during the interrupt grace still exits 0.
The environment variables kyacode itself reads (KYA_API_KEY, which kyacode
exports into harness sandboxes, is covered under Harness wiring):
| variable | effect |
|---|---|
KYA_GATEWAY |
override the gateway base URL (wins over config.json) |
KYA_GATEWAY_INSECURE |
a value with non-whitespace content allows plaintext http:// to loopback hosts only |
Wiring is injected at spawn time: into the launched process tree, or into a
throwaway sandbox that your normal harness sessions never read. Rows marked
yes are materialised in a per-launch directory
~/.kyacode/<harness>-<pid>-<random>/ (0700) that is removed when the launch
returns, including on Ctrl-C/SIGTERM/SIGHUP. The first three harnesses are
pure env injection (they leave no file behind), so they are listed first.
| harness | wiring | persisted? |
|---|---|---|
| claude | env: ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN |
no |
| opencode | env: OPENCODE_CONFIG_CONTENT (inline JSON) |
no |
| qwen | env: OPENAI_BASE_URL + OPENAI_API_KEY + OPENAI_MODEL |
no |
| codex | sandbox: CODEX_HOME (config.toml + auth.json, plus models.json when the catalog renders) |
yes |
| cline | sandbox: CLINE_DATA_DIR (providers.json) |
yes |
| droid | sandbox: HOME (.factory/settings.json) |
yes |
| pi | sandbox: HOME (.pi/agent/models.json) |
yes |
| openclaw | sandbox: HOME (.openclaw/openclaw.json) |
yes |
| hermes | sandbox: HERMES_HOME (config.yaml) |
yes |
| omp | sandbox: PI_CODING_AGENT_DIR (models.yml) |
yes |
| dsh | sandbox: settings.yaml + patch (key by env reference) | yes |
Five sandbox rows (codex, droid, dsh, openclaw and pi) additionally export
KYA_API_KEY; the harness config files either reference it (codex
env_key, dsh apiKeyEnv) or carry a copy.
Rows that replace HOME (droid, openclaw and pi) redirect all of the
harness's runtime state (sessions, caches) into the sandbox, which is
discarded when the launch ends.
claude, codex, droid, dsh, omp, openclaw, opencode and pi fetch the gateway's full model catalog at launch, so the harness's own picker can select among gateway models. droid, dsh, omp, openclaw, opencode and pi list every served id; codex lists the chat-capable ids when its catalog renders; claude renders a bounded four-slot alias picker.
A model you pass becomes the default;
with no model given, droid, dsh, omp, openclaw and pi pin the first real
id of a fetched catalog as the default
(claude, codex and opencode never write a default: claude and codex
refuse a model-less launch outright, so the typed model rides the
spawn-time wiring, and opencode's own picker decides at startup, a choice
deliberately held until its boot behaviour is re-verified).
If the catalog is unavailable (a transient gateway outage) and no model was
passed, no default is written anywhere and the catalog degrades to the
kya-model placeholder row; what each harness then does at startup is its
own fallback behaviour.
omp, openclaw, opencode and pi take a BARE model id: they scope it
themselves with the kya/ provider prefix, so a provider-scoped argument is
refused at launch. The remaining harnesses wire the model their own way:
droid takes a bare id on the command line (its CLI refuses scoped
custom-model ids), dsh carries it in the sandbox config, and claude, cline,
codex, hermes and qwen take the typed model as their single entry model.
Check kyacode models for the current list.
Claude Code sizes a model's context window from the model id string, so a gateway alias needs a hint (verified on Claude Code 2.1.261). The rules:
model id as passed to kyacode launch |
window Claude Code assumes |
|---|---|
contains [1m] |
1,000,000 |
unresolvable, no [1m], does not start with claude- |
200,000 |
starts with claude-, no [1m] |
Claude Code's own native resolution (not measured here) |
For the third row and any other unmeasured id, check the assumed window
in-session with /context.
So pass the suffix through: it is Claude Code's own convention, stripped
before the request leaves for the provider. The gateway never needs a
model literally named glm-5.3-flash-nvfp4[1m]:
kyacode launch claude 'glm-5.3-flash-nvfp4[1m]'Two caveats:
- The suffix is read per variable: the
opus/sonnetaliases and--modelare each read on their own, so for a gateway id keep the suffix on the one you select. - Claude Code only assumes the window. The model must actually serve it
(
--max-model-lenon the inference side), otherwise a long prompt fails with a prompt-too-long error rather than compacting.
Compaction needs the same kind of hint, and gets less of one: on a [1m] id
Claude Code runs no threshold auto-compact at all and defers to the gateway
rejecting an over-limit request (verified on Claude Code 2.1.302). A long
session therefore grows right up to the window before anything happens, and
/compact itself re-sends the whole conversation, so a session already past
the limit recovers only through Claude Code's own shrink-and-retry, which
keys on the gateway's error wording. Prevent it instead: run
/autocompact 800000 once in a session on the model. It is saved under the
model's base name in Claude Code's per-model settings (the [1m] spelling
matches), is capped at the window Claude Code assumes for the model, and
applies to every later session; the threshold lands about 33,000 tokens
below the configured value, so against a serving limit of 1,048,576 tokens
the compaction request (full history plus a 32,000-token summary budget)
fits with room to spare, and 800,000 keeps a wide margin for the estimate
error. For other setups keep the value at roughly three quarters of the
enforced context limit. Two alternatives:
CLAUDE_CODE_AUTO_COMPACT_WINDOW=800000in the environment behaves the same and is capped the same way, but it is process-global: it overrides per-model/autocompactsettings in every session launched from that shell, so prefer/autocompacton mixed-window setups.CLAUDE_CODE_MAX_CONTEXT_TOKENSdoes nothing on its own for a[1m]id (the[1m]handling precedes it).
With a window set, the status line switches from "% context used" to a "% until auto-compact" countdown; that is the expected form.
[1m] is Claude Code only; it means nothing to Codex, opencode, Qwen Code
or the other harnesses. To raise Qwen Code's window, set
generationConfig.contextWindowSize on the model's modelProviders entry
in ~/.qwen/settings.json.
| location | mode | lifetime |
|---|---|---|
~/.kyacode/token |
0600 | until unauth |
~/.kyacode/config.json |
0600 | manual |
~/.kyacode/<harness>-<pid>-<random>/ |
0700 | per launch |
| child process env (env rows) | n/a | dies with the child |
On Windows, ~ above is your user profile: the store lives at
%USERPROFILE%\.kyacode.
tokenis written through an exclusive temp file created at 0600 (a umask can only strip bits from that, never add them back) and chmod'd 0600 on the open handle before the rename, so the key is never briefly world-readable. The 0600 is a unix guarantee: on Windows Go'sos.Chmodmaps the mode to the read-only attribute only, and NTFS ACLs govern access.config.jsonis written 0600 and re-chmod'd 0600 on every save, so even a pre-existing lax-mode file is tightened rather than tolerated. Same unix scoping as the token above.- The sandbox root's
0700is a unix guarantee like the modes above; on Windows, NTFS ACLs govern access. kyacode statusshows only a short preview of the stored key (first 3 and last 4 characters; keys shorter than 16 characters show no preview at all), never the full value.kyacode modelssends the key nowhere when the stored gateway cannot be read or validated (a config parse error, a file-shaped~/.kyacode, an invalidKYA_GATEWAYoverride): the fetch fails instead of silently falling back to the default gateway.- Wiring is inherited by grandchildren of the harness (accepted cost of the no-proxy design: the harness talks straight to the gateway, with nothing local in between).
- Nothing personal belongs under
~/.kyacode. The orphan sweep removes any directory matching the sandbox shape<harness>-<pid>-<random>(older than 24 h), so user-named directories sharing a harness prefix (codex-archive,pi-notes) are never touched, but keep personal data out of this tree anyway. The age bound is the only guard: there is deliberately no PID-liveness check, and sandbox mtimes are written once at build time and never refresh, so a single launch running longer than 24 h can have its sandbox swept by a concurrentkyacode status. kyacode statusmay printWARNING: orphan sweep incompletewhen the~/.kyacodescan itself fails (e.g. it is not a readable directory); the command still succeeds.
Warning
SIGKILL (or a second Ctrl-C) kills kyacode before its deferred cleanup
runs, orphaning the sandbox and env wiring: no handler can intercept
SIGKILL, and the second Ctrl-C resets the signal disposition so it kills
immediately. On Windows the first Ctrl-C ends the launch exactly like
POSIX: the interrupt ladder (kyacode's staged Ctrl-C handling) delivers a
process-group break to the harness tree (including the .cmd shim and its
node/bun descendants), then force-kills the whole tree, which also catches
grandchildren that daemonized away from the group. Run kyacode status
later; it sweeps orphans.
- Any gateway command (
doctor,models,launch) fails withno token stored (run `kyacode auth`): runkyacode authand paste the key;kyacode statusshows whether a key is stored. - The harness launches but every model call fails with an auth or model
error: the spawn wiring only points the harness at the gateway. Run
kyacode doctor(a401/403row means the key was refused, so re-runkyacode authwith a fresh key) and confirm the id inkyacode models. - A long session on a
[1m]model never auto-compacts, and/compactfails with a 400 about the input exceeding the model's context length: expected on a 1M id, where Claude Code defers compaction to the gateway. Run/autocompact 800000once in a session on the model (it persists for that model and re-arms threshold compaction with headroom to spare); see 1M context with Claude Code for the alternatives and for recovering a session that is already over the limit. - The one-line install exits 0 with nothing installed: when the dist
directory does not yet serve the requested script, curl fails (its own
error still prints on stderr) and the pipe feeds
shan empty script, which exits 0 (the site's copy is behind the GitHub release). Retry later, or fetch the binary from the releases page directly. - A manual fetch from the GitHub release (the Fallback section) returns 404 when the release or the asset is missing; check the releases page.
- A launch or probe fails with
gateway redirected to <url> (refused: the hop would carry the key): the URL answers with a redirect (a CDN or proxy front); pointkyacode gateway <url>at the origin that answers directly. doctorprobes fail: check thegateway:line doctor prints first. Fix a wrong base URL withkyacode gateway <url>; a401/403row means the key was refused, so re-runkyacode authwith a fresh key; anything else may be a transient gateway outage.doctorshows 404s on green rows: expected. Four of the five probes deliberately send a nonexistent model, and a404row readingprobe miss confirmedis the pass evidence for those rows. A confirmed probe miss proves the route parses requests and consults its models, never that inference, streaming, or tool calls work (doctor prints that honesty note on every run).- Leftover
~/.kyacode/<harness>-<pid>-<random>/directories:kyacode statussweeps them; see Storage and security boundaries. launchrefuses with<harness> is not installed; install it first: the harnesses without an official installer (see the auto-install note under Commands) must be installed by you first;kyacode statusshows which harness binaries were found.- A hand-edit that breaks
~/.kyacode/config.jsonfails every gateway-reading command (doctor,status,models,launch) withparse <path>: ...; there is no silent fallback, andKYA_GATEWAYdoes not bypass it (the parse error fires before the override).kyacode gateway <url>repairs the setting without reading the old file. If~/.kyacodeitself is a regular file rather than a directory, the error reports it: remove or rename that file, then re-runkyacode authandkyacode gateway <url>.
The install one-liners at the top are all you need. If you prefer to fetch
the binary from the GitHub release yourself (an air-gapped prefetch, a
mirror-averse environment), release assets follow the pattern
kyacode-<goos>-<goarch>[.exe], each with a companion .sha256 sidecar.
Windows: fetch kyacode-windows-amd64.exe from the dist directory
(https://kyaky.ai/kyacode/) or download it from the
releases page.
A verified fetch for POSIX shells:
fetch_kyacode() {
local os arch base t
os=$(uname -s | tr '[:upper:]' '[:lower:]'); arch=$(uname -m)
case "$arch" in
x86_64) arch=amd64 ;;
aarch64|arm64) arch=arm64 ;;
*) echo "kyacode: unsupported architecture '$arch' (need x86_64 or arm64/aarch64)" >&2; return 1 ;;
esac
base="https://github.com/kyaky/kyacode/releases/latest/download"
t=$(mktemp -d) || return 1
curl -fL -o "$t/kyacode-$os-$arch" "$base/kyacode-$os-$arch" \
|| { rm -rf "$t"; echo "kyacode: binary download failed" >&2; return 1; }
curl -fL -o "$t/kyacode-$os-$arch.sha256" "$base/kyacode-$os-$arch.sha256" \
|| { rm -rf "$t"; echo "kyacode: checksum file download failed" >&2; return 1; }
(cd "$t" && { sha256sum --check "kyacode-$os-$arch.sha256" 2>/dev/null \
|| shasum -a 256 --check "kyacode-$os-$arch.sha256"; }) \
|| { rm -rf "$t"; echo "kyacode: checksum mismatch - refusing to install" >&2; return 1; }
mkdir -p ~/.local/bin || { rm -rf "$t"; return 1; }
if ! install -m 0755 "$t/kyacode-$os-$arch" ~/.local/bin/kyacode; then
rm -rf "$t"
return 1
fi
rm -rf "$t"
return 0
}
fetch_kyacode && echo "installed to ~/.local/bin/kyacode"Every stage gates the install: a download error (404, truncation) or a
checksum mismatch fails loudly and exits non-zero before install
runs, and the scratch directory is removed either way. The arch case
refuses unmapped uname -m values up front instead of requesting a wrong
asset name.
Or with gh only:
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$(uname -m)" in
x86_64) arch=amd64 ;;
aarch64|arm64) arch=arm64 ;;
*) echo "kyacode: unsupported architecture '$(uname -m)' (need x86_64 or arm64/aarch64)" >&2; false ;;
esac && gh release download --repo kyaky/kyacode --pattern "kyacode-$os-$arch*"(the unmatched case ends in false, so gh never runs with an
unset/widened glob; the exit status carries the failure).
gh alone stops at the download: it drops kyacode-$os-$arch and its
.sha256 sidecar into the working directory and neither verifies nor
installs them; for the verified install, use the fetch above.
Go ≥ 1.27. There is intentionally no make and no build script: the whole
program is a single module with no cgo.
# local build (darwin/linux/windows, cgo disabled, stripped, trim-pathed)
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/kyacode ./cmd/kyacodeCross-compiling for a release target follows the same recipe with GOOS /
GOARCH set, e.g.:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -ldflags="-s -w" -o dist/kyacode-linux-arm64 ./cmd/kyacodeThe full target matrix is in
.github/workflows/release.yml.
A release build additionally stamps the tag as its version: release.yml adds
-X main.Version=<tag> to the same -ldflags, so a binary built exactly
per the recipe above reports v0.0.0-dev under kyacode version.
cmd/kyacode/ CLI entrypoint (dispatch and subcommands; the ladder needs no CLI code)
internal/config/ gateway URL + token path + persistence
internal/rootdir/ the ~/.kyacode name's one owner (pure path resolution; consumers apply their own creation policy)
internal/doctor/ pre-flight probes over the gateway module (entry protocols + compat + catalog)
internal/harness/ runner registry: 11 harnesses (env-only + sandbox); sandbox materialisation and the <harness>-<pid>-<random> grammar (internal/harness/sandbox)
internal/hygiene/ CI/README self-gates: workflow pins, README prose pins, executable install snippets
internal/gateway/ the one keyed transport to the gateway: /v1 join, Bearer shape, typed redirect refusal, /v1/models fetch
internal/ladder/ the interrupt ladder: published handoff, escalation rungs, exit contract
internal/procctl/ process-control primitives (group config, graceful rung, TERM rung, tree force)
scripts/ the installer pair (install.sh, install.ps1)
assets/ README banner artwork (banner.png)
Decision records and internal analysis notes are intentionally not tracked
in git; CONTEXT.md, the project's vocabulary of record, is tracked at the
repo root.
kyacode is also a demonstration: local AI coding agents on commercial and open-source harnesses carrying a software project's full lifecycle (research, development, maintenance, release) through GitHub, with all model inference on the maintainer's own gateway under local data governance and sovereignty. 'Local' covers model inference; the harnesses keep their own upstream update and telemetry channels. The checkable record: the commit history, the CI and release workflows, and the hygiene tests that pin the docs to the code.
Development ran on kyacode itself: in the private-era version numbering (the
public releases start at v0.1.0), versions through v4.2 were driven by the
opencode and
qwen-code harnesses, every version
after v4.2 by Claude Code, on
the same local gateway models (glm-5.3-flash-nvfp4, qwen3.8-flash-next
and qwen3.8-27b-nvfp4), all of it built entirely by AI coding agents,
every change supervised, reviewed and accepted by a human maintainer.
kyacode's design took shape against Restech Technology Services, UNSW's self-hosted high-performance inference gateway, and this project owes that gateway a direct debt: its free model access is what made the work possible at all. kyacode is an independent project and is not affiliated with UNSW; the acknowledgement is where the lineage ends.
Bug reports and feature requests go to GitHub issues. For anything security-sensitive, please reach out privately first (see kyaky.ai) rather than opening a public issue.
Apache License 2.0. See LICENSE.

