Configuration and security reference¶
This page lists every Code Akos setting and explains how projects, tokens and the two network listeners work. Most people never need it: the setup window covers the common settings. To install Code Akos, see installation.
What a project is¶
A project is a repository, the branch to work on, and the GitHub token to do it with. Its ID is the number at the end of the DSN.
- The branch is the one you give, not GitHub's default. Errors are filed against it, fixes are based on its latest commit, and pull requests target it.
- Tokens are stored encrypted (AES-256-GCM) in
projects.db, never in.env, and are never sent to the browser (only the last 4 characters, to tell tokens apart). The key issecret.key(mode 0600), beside it. - What that does and does not protect: a copied database or backup contains no usable token. Someone who can read your user's files can still read the key beside it, so this is the same trust as an SSH private key, not an OS keychain.
- A project can have a separate token for the resolver (pushing a branch and opening a pull request need more access than filing issues). Without one, the main token is used.
- Each project's repository is cloned once, when it is added, into
repos/as a bare, shallow (--depth 1), single-branch clone, and fetched before every fix. One clone serves every branch of a repo. - The check command runs through a shell, in a throwaway copy of the repository, before and after each fix. If it already fails before the fix, the resolver skips the issue; if it fails after, the pull request says it is unverified. It runs as you, on your machine, so only put commands there that you would run yourself.
All of it lives in one data folder, ~/.code-akos by default (ORCH_DATA_DIR).
Two listeners¶
One process, two sockets, and the split matters:
| Dashboard | Error ingest | |
|---|---|---|
| Default | 127.0.0.1:7420 |
127.0.0.1:3000 |
| Auth | token cookie + Host allow-list + Origin check |
optional sentry_key only |
| CORS | none (same-origin only) | * |
| Serves | the UI and the API | the two Sentry endpoints and /healthz, nothing else |
Sentry SDKs, browsers included, post cross-origin with no cookie, so none of the dashboard's checks can apply to them. Rather than weaken those checks, ingest gets its own socket with nothing else on it. It still binds loopback by default, so only apps on this machine can report until you set ORCH_ERRORS_INGEST_HOST=0.0.0.0 (which prints a warning at startup). Set ORCH_ERRORS_DSN_PUBLIC_KEY to require a key.
Security¶
This server holds your GitHub tokens and can push code, so:
- It listens on 127.0.0.1 only, unless you set
ORCH_DASHBOARD_HOST(the Docker image does; publish it on127.0.0.1only). - Requests must have a
Hostoflocalhost/127.0.0.1/[::1]on Code Akos's port (blocks DNS rebinding), and state-changing requests are rejected ifOrigin/Sec-Fetch-Sitesay they came from another site. - Every
/apiroute needs a secret token, kept in<data folder>/token(mode0600). The link printed at startup exchanges it for anHttpOnly; SameSite=Strictcookie. Treat the token file like an SSH key. - Strict CSP,
X-Frame-Options: DENY,nosniff,no-referrer, andno-storeon API responses. - Git and the model's tools use argument arrays. The only shell is your own check command.
Configuration¶
Settings live in a .env file. The desktop app's setup writes it on first launch, and Settings in the dashboard header edits it later. From source, the terminal setup does the same; you can also copy .env.example to .env and edit it, where every variable has a default.
The setup, in the desktop app and in the terminal, differs from a hand-written .env in three ways:
- It always turns on error tracking and the resolver.
ORCH_ERRORS_ENABLED=0andORCH_RESOLVER_ENABLED=0still work when set by hand. - It requires at least one model, because the resolver needs one.
- It writes only values it has checked: the ports are free, the Ollama address answers, API keys are accepted, and the models are ones the provider lists. Then the server's own config checks run on the result before anything is written.
| Variable | Default | |
|---|---|---|
PORT |
7420 |
The dashboard. |
ORCH_DATA_DIR |
~/.code-akos |
Where the token, databases, key and clones live. |
ORCH_TOKEN_FILE, ORCH_SECRET_KEY_FILE, ORCH_PROJECTS_DB, ORCH_REPOS_DIR |
inside ORCH_DATA_DIR |
Move one of those out of the data folder. |
ORCH_GITHUB_API_URL |
https://api.github.com |
For GitHub Enterprise. |
ORCH_GITHUB_CLONE_URL |
https://github.com/{repo}.git |
Where to clone from, with {repo} for owner/name. |
ORCH_OLLAMA_URL |
unset | Address of a local Ollama server, which runs the model for triage and fixes. The resolver always tries Ollama at http://localhost:11434; triage uses it only when this is set. |
ORCH_OLLAMA_MODEL |
qwen2.5-coder:7b |
The model Ollama is asked to run. |
ORCH_DEEPSEEK_API_KEY |
unset | Turns on DeepSeek as a provider for triage and the resolver. |
ORCH_DEEPSEEK_MODEL |
deepseek-flash |
Or deepseek-v4-pro. Thinking mode is always off. |
ORCH_DEEPSEEK_API_URL |
https://api.deepseek.com |
|
ORCH_ANTHROPIC_API_KEY |
unset | Turns on Anthropic as a provider for triage and the resolver. |
ORCH_ANTHROPIC_MODEL |
claude-haiku-4-5 |
|
ORCH_ANTHROPIC_API_URL |
https://api.anthropic.com |
|
ORCH_LLM_PROVIDERS |
ollama,deepseek,anthropic |
The providers to try, in order, for both triage and the resolver; the first is used and the rest are fallbacks when it fails. A provider that is not set up is skipped by default, and is an error when you name it here. |
ORCH_TRIAGE_PROVIDERS / ORCH_RESOLVER_PROVIDERS |
ORCH_LLM_PROVIDERS |
The same, for one purpose only. |
With no provider set up for triage, new errors are triaged by built-in rules. When providers are set up and all of them fail, the rules are not used as a substitute: the error is recorded as ERRORED and can be triaged again from the dashboard.
Errors¶
| Variable | Default | |
|---|---|---|
ORCH_ERRORS_ENABLED |
on | 0 leaves the workflow out. |
ORCH_ERRORS_INGEST_PORT |
3000 |
|
ORCH_ERRORS_INGEST_HOST |
127.0.0.1 |
|
ORCH_ERRORS_DSN_PUBLIC_KEY |
unset | When set, ingest requests must carry this sentry_key. |
ORCH_ERRORS_PUBLIC_URL |
unset | The address apps use to reach ingest, such as http://code-akos:3000 for a container on the same Compose network. DSNs are built from it instead of from the host and port. It must be an http or https address with no path, query or credentials. |
ORCH_ERRORS_GITHUB_LABELS |
none | Labels applied to new issues. |
ORCH_ERRORS_MIN_LEVEL |
error |
A threshold: that level and every level above it are filed on GitHub (error files error and fatal; fatal files crashes only). The order is debug, info, warning, error, fatal. Lower levels are still stored and triaged. |
ORCH_ERRORS_COMMENT_THRESHOLDS |
100,1000,10000 |
Event counts at which it comments on the GitHub issue. |
ORCH_ERRORS_RETENTION_DAYS |
30 |
Raw events older than this are pruned hourly; issue rows and counters stay. 0 keeps everything. |
ORCH_ERRORS_DB |
<data>/errors.db |
What reaches GitHub. Every error is kept in Code Akos and listed on its project's page. A GitHub issue is opened only for an error that carries a stack trace (a bare log line gives a fixer little to go on), unless the project ticks Also file errors without a stack trace on GitHub. Grouping uses the exception type, the crashing file (origin, query string and content hashes stripped) and that frame's source line text, or its function name when the SDK sent no source. The message is not used, so changing IDs in it do not split a group. An event without a stack is grouped by its message with numbers, UUIDs and hex IDs replaced. The SDK's fingerprint (including {{ default }}) overrides all of this. Groups are per project and per service tag.
Resolver¶
| Variable | Default | |
|---|---|---|
ORCH_RESOLVER_ENABLED |
on | 0 leaves the workflow out. |
ORCH_RESOLVER_DB |
<data>/resolver.db |
|
ORCH_RESOLVER_POLL_INTERVAL_MS |
300000 |
Minimum 30000. |
ORCH_RESOLVER_MAX_CONCURRENT_FIXES |
3 |
|
ORCH_RESOLVER_MAX_TURNS |
20 |
The most model turns one fix attempt may take before it fails with "exceeded the maximum number of turns". |
ORCH_RESOLVER_MAX_ATTEMPTS |
3 |
How many failed attempts one issue gets before the resolver stops on its own. A failed attempt waits 15 minutes before the next try, doubling each time. Running an issue from the dashboard ignores the limit. |
ORCH_RESOLVER_RETRY_SKIPPED_ATTEMPTS |
off | Testing aid: re-attempt SKIPPED issues each poll. PR_OPEN is never retried. |
The resolver attempts every open GitHub issue Code Akos filed for an existing project, whatever its triage tags, unless an earlier attempt opened a pull request or was skipped. A single attempt is capped at ORCH_RESOLVER_MAX_TURNS model turns (20 by default). Every turn is also appended to a file per issue, <data folder>/logs/<owner>-<repo>-issue-<n>.log (folder set by ORCH_RESOLVER_LOG_DIR), and a failed attempt's error names that file. It runs your check command as you, on your machine.
Running from source¶
For a headless server, or working on Code Akos itself. Needs Node 24+ and git, on Linux or macOS.
git clone https://github.com/Ayesh96/code-akos.git && cd code-akos
npm install # also installs the UI's dependencies
npm start # builds the UI if it is stale, then serves it
The first npm start in a terminal runs the same setup as the desktop app and writes .env; npm run setup changes it later, starting from the current values. npm start then prints http://localhost:7420/?token=…: open it once, and the token is kept in an HttpOnly cookie. curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/healthz prints 200 when ingest is up.
Each release also has a tarball with the UI prebuilt, so there is no build step: check it against sha256sums.txt, unpack it, and run node bin/code-akos.mjs.
Running in Docker¶
A container image is published at ghcr.io/ayesh96/code-akos. Inside the container the dashboard listens on all interfaces (ORCH_DASHBOARD_HOST=0.0.0.0), so publish it on 127.0.0.1 only. ORCH_DASHBOARD_PUBLIC_PORT adds the published port to the allowed Host values when it differs from PORT. See Running in Docker.
Development¶
server/ Express API (TypeScript, run natively by Node)
app.ts the dashboard app (loopback, token-checked)
ingest.ts the public ingest listener: no cookie, no Origin check, ingest routes only
projects/ projects, encrypted tokens, repo clones, the GitHub check, and the Projects routes
workflows/
errors/ Sentry ingest, grouping, triage, GitHub issues
resolver/ polls those issues, attempts a fix, opens a PR
web/ React + Vite + Tailwind v4 + shadcn/ui (Radix). See DESIGN.md
test/ real git and real SQLite; only GitHub's network API and the paid model are faked
The only runtime dependency of the server is express; SQLite is Node's built-in node:sqlite.
npm run dev # API with auto-restart + Vite hot reload on http://localhost:5173
npm test # server tests + UI unit tests
npm run typecheck
npm run setup # the terminal setup; writes .env
python3 test/setup-wizard.pty.py # drives the terminal setup in a pseudo-terminal; works in scratch copies, never your .env
Desktop app¶
desktop/ is an Electron shell for macOS, Windows and Linux. It forks bin/code-akos.mjs in Electron's own Node (so the machine needs no Node install), shows the setup as a window on first launch (desktop/onboarding.html, the same checks as the terminal setup through scripts/setup-checks.mjs), and opens the dashboard in a window. Settings in the dashboard header, or Code Akos › Settings… (⌘,), reopens the setup filled in from .env (File › Settings…, Ctrl+, on Windows and Linux). Saving restarts the server; if it will not start, the previous .env is restored and the previous server started again.
cd desktop
npm install
npm start # run from the repo (uses the repo's .env)
npm run dist:mac # build release/code-akos-<version>-mac-arm64.dmg and -mac-x64.dmg (Intel)
npm run dist:win # an NSIS .exe installer
npm run dist:linux # an AppImage
npm run test:e2e # Playwright against the built macOS app; build first
Pushing a v* tag builds all three on GitHub Actions and attaches them to the release, unsigned. Only the Apple Silicon build is tested.
The built app looks for a newer release (desktop/updates.js) 15 seconds after the dashboard opens and then every 24 hours, using GitHub's latest-release API, and offers this computer's file in a dialog. It installs nothing itself. The automatic check, and a version the user chose to skip, are kept in update-state.json in the user-data folder; a run from the repository (npm start) never checks on its own.
In the built app, .env lives in the app's user-data folder, separate from the repo's and kept across updates: ~/Library/Application Support/Code Akos/.env on macOS, %APPDATA%\Code Akos\.env on Windows, ~/.config/Code Akos/.env on Linux. The server runs with that folder as its working directory. Builds before 1.1.0 kept it inside the app; the first launch of a newer build copies it over. The macOS build is ad-hoc signed (mac.identity: "-"): an Apple Silicon Mac refuses to run an Electron app with no signature at all. It is not notarized, so macOS blocks the first open of a downloaded copy until it is allowed in System Settings › Privacy & Security. Removing that step for users needs a Developer ID certificate and notarization; on Windows, a code-signing certificate.
The end-to-end tests give each test its own APFS clone of the built app, fake Ollama, DeepSeek and Anthropic servers, and a stubbed folder picker, so they never touch ~/.code-akos or a real API. The cases are listed in desktop/tests/CASES.md.
To add another workflow, implement Workflow from server/workflows/types.ts (id, title, routes(router), optional start/stop, and ingestRoutes(router) only if it needs unauthenticated outside traffic), switch it on in server/workflows/index.ts, and register a panel for its id in web/src/components/extensions.ts.
DESIGN.md documents the tokens, components, accessibility rules and copy conventions.