kārya
docs / start

Getting started

Install Karya, add a Gemini key, and try the terminal UI. Karya is in active development: the TUI works today, and the agent loop, sandbox and undo arrive over the next milestones.

status
Working today: the TUI, the scripted demo, live Gemini streaming, threads and prompt history. Not yet: tools, sandbox, undo, sessions. See the roadmap →

Install

Karya is a single Go binary and needs Go 1.25.4 or newer:

$ go install github.com/prateek041/karya/cmd/karya@latest

Prebuilt release binaries for macOS and Linux are planned for launch.

Configure

Get a key from Google AI Studio and export it, or put it in a .env file in the directory you run Karya from. An exported variable wins over the file.

export GEMINI_API_KEY=…

Run

There are three ways to start Karya today:

$ karya -demo   # scripted demo, no key needed
$ karya -live   # stream answers from Gemini
$ karya         # the TUI on the protocol, with the demo core

The demo below shows where the default mode is heading: the read and the sandboxed test run go ahead on their own, and the edit waits for you.

Karya~/src/tasks
›add a --json flag to the list command and make the tests pass
I'll read the list command, add a --json flag that encodes the tasks with encoding/json, then run the test suite.
· read cmd/list.go lines 1–86
RunE builds the table. Adding the flag and a JSON branch there.
editcmd/list.go
awaiting approval
@@ -14,7 +14,12 @@ func newListCmd() *cobra.Command
cmd := &cobra.Command{Use: "list"}
+ var asJSON bool
+ cmd.Flags().BoolVar(&asJSON, "json", false, "print as JSON")
cmd.RunE = func(c *cobra.Command, _ []string) error {
tasks := store.List()
+ if asJSON {
+ return json.NewEncoder(c.OutOrStdout()).Encode(tasks)
+ }
return printTable(c.OutOrStdout(), tasks)
[a]pprove[d]eny
waiting on you · [a]pprove [d]eny
›
arise, resolved to fight

Keys

entersend; during a run, queue it (ctrl+x stops the run and sends now)
shift+enternew line (alt+enter and ctrl+j also work)
shift+tabcycle the mode: normal → accept edits → plan
ctrl+gwrite the prompt in $VISUAL / $EDITOR
↑ / ↓prompt history, kept in $XDG_STATE_HOME/karya/history
@ / !mention a file (attached for the model) / run a shell command
ctrl+rthreads, grouped by project
/commands: /undo, /mode, /notify, /threads, /editor, /theme, /exit, …
?every key

Modes and approvals planned · M2

Karya does not ask before every command. Shell commands run inside the OS sandbox, so they can run freely; edits show a diff. shift+tab cycles the mode.

moderead · list · searchwrite · editbash
planrunrefusedrun · read-only sandbox
defaultrunask, with diffrun · sandboxed
accept-editsrunrunrun · sandboxed
--no-sandboxrunaskask every time

Leaving the sandbox always asks

An unsandboxed run or a domain that is not on the network allowlist always asks, in every mode. You can answer once, for this session, or always (saved as a rule).

Denying a call

Deny with a reason and the call does not run. The reason goes back to the model as a structured result, so it can propose something else or stop. A denied edit leaves the file byte-identical.

editcmd/list.go
✕ denied
@@ -14,3 +14,3 @@
- return printTable(c.OutOrStdout(), tasks)
+ return printJSON(c.OutOrStdout(), tasks)

Undo planned · M3

Before a turn's first side effect, Karya snapshots the working tree to a shadow git directory outside the project. This covers changes from every tool, bash included. Files the project ignores, and effects outside the root, are reported as not covered.

/undo          restore the tree from before the last turn
/rewind <n>    go back n turns
/redo          re-apply what was undone

Resume a session planned · M1, M5

Every session is an append-only JSONL log stored outside the project. Logs are keyed to the repository's git remote rather than its local path, and contain no absolute paths or hostnames, so you can resume on any machine with a clone of the same repository. karya sync moves them end-to-end encrypted through a folder, bucket or git ref you own.

$ karya resume <session-id>

On resume, Karya compares what it recorded with the live repository and gives the model a drift note. The note covers:

HEADrecorded SHA against the current SHA
working treerecorded dirty flag against the current state
platformoperating system, if it changed
drift note
HEAD moved from a1b2c3 to d4e5f6, working tree dirty, platform changed from darwin to linux.

A session that stopped at a cost or step limit is resumable the same way.

Reference

environment
GEMINI_API_KEYworks today · required
Your Gemini API key. Karya also reads it from a .env file in the working directory; a real exported variable wins over the file.
GOOGLE_API_KEYworks today · optional
Alternative name for the Gemini key. Wins if both are set.
ANTHROPIC_API_KEY · OpenAI-compatibleplanned · M4
Anthropic and OpenAI-compatible providers (OpenRouter, DeepSeek, Qwen, Ollama, vLLM, LM Studio). Keys never reach logs, sessions or sync bundles.
commands and flags
karyaworks today
Start the TUI in the current directory, talking to the demo core.
karya -liveworks today
Stream answers straight from Gemini, without the core. Threads are saved under $XDG_DATA_HOME/karya/threads.
karya -demoworks today
Play the scripted demo. No API key needed.
karya -theme lightworks today
Colour theme: dark or light.
--model · --mode · --max-cost · --max-stepsplanned · M1–M3
Pick the model and mode, and set hard budgets for the session.
--root <dir> · --no-sandboxplanned · M2
Choose the project root. Run bash without the sandbox, in which case every command asks.
karya run "<task>" [--json]planned · M1
Run one task headless. Exit codes: 0 done and verified, 1 failed, 2 limit reached, 3 verification failed, 4 interrupted.
karya resume [<id>] · sessionsplanned · M1
List and resume sessions, on this machine or another clone of the same repository.
karya sync · doctorplanned · M4–M5
End-to-end encrypted session sync, and a health check for the sandbox, keys and config.