Repository navigation
g023 Code 1.3.3
g023 Code — Release 1.3.3
Version: 1.3.3
Date: 2026-08-21
Supersedes: 1.3.2
Artifacts: g023-code-1.3.3.tar.gz, g023-code-1.3.3.zip, unpacked tree in g023-code-1.3.3/
Pure-Python DeepSeek V4 powered coding agent. Subagent-First architecture,
terminal-native UI built on rich + prompt_toolkit.
1.3.3
The theme of this release is money: knowing what the API costs before,
while, and after you spend it. DeepSeek moved to tidal (peak/off-peak) pricing
on 2026-08-17, and 1.3.3 makes that visible and steerable; it also adds a
second, third and fourth way to see images; it makes every edit recoverable;
and it lets settings live in two scopes instead of one. 147 tests, all passing.
Surge pricing — /surge
DeepSeek bills peak and off-peak separately: peak hours are 09:00–12:00 and
14:00–18:00 Beijing time (UTC+8), and off-peak is exactly half of peak.
g023 now knows those windows and does three things with them:
- It shows them on your clock.
ds_times.jsonanchors the windows to
Beijing wall-clock time; the CLI converts them to the machine's local
timezone and prints every time in both AM/PM and 24-hour form. - It prices with them.
/costand the status bar split regular vs surge
(2×) rates per model, straight fromds_pricing.json— so the number you
see during a peak hour is the peak number, not a stale off-peak estimate.
The status bar showsSURGE 2×while a peak window is active. - It can pause for them.
/surge onstops sending requests from
surge_pause_buffer_minutes(default 5) before the first peak of the day
until that long after the last one ends, then resumes automatically; the CLI
waits out the window instead of reading input, and Ctrl-C bypasses it for
that pass./surge notify on|off(default on) banners the transitions.
/surge status also counts down — minutes to the next surge and how long it
will last — and shows the pause window it would use. surge.py is pure local
arithmetic: no API call, no network. The price sheet lives in the two data
files (ds_pricing.json, ds_times.json), read from the install folder or
the project root, so updating a price is editing JSON, not code.
OpenRouter vision — /or
Vision was previously Ollama-only. There is now a three-backend split,
selected with /vision backend none|ollama|deepseek|openrouter:
openrouter— the newopenrouter_client.pytalks to OpenRouter using
theOK.datkey. Models come from./OR_VISION.json(project folder) in
priority order; when one returns HTTP 429 the next on the list is tried.
Default modelgoogle/gemma-4-26b-a4b-it:free. Free:freemodels are
capped at 50 requests/24h for accounts under $10 of lifetime credits, and
up to 1000/24h after that —/or tier free|creditstells g023 which
ceiling you are on, and/orshows today's usage against it.deepseek— DeepSeek's own experimental multimodal model,
deepseek-v4-flash-vision-exp, billed on the sameK.datkey at exactly
the token rates ofdeepseek-v4-flash. The wire format is selectable with
/vision endpoint responses|chat_completions(default:responses, the
program's native format).ollama— unchanged: local or remote daemon, models filtered to the
ones the daemon reports as vision-capable.
subagents/vision.py + subagents/router.py own the dispatch: AnalyzeImage
is routed to the active backend, and answers are cached by image hash +
question + backend + model in the SQLite cache. While vision is disabled the
tool is not even offered to the orchestrator.
WriteFile backups — a bad write is one copy away
WriteFile replaces the entire file, and a write reconstructed from a summary
can silently truncate it. Every overwrite now first snapshots the previous
version to .g023/backups/<relative-path-to-file>/<timestamp>-<sha256-prefix>.bak,
mirroring the file tree; only the newest few versions per file are retained
(default 5). The write result line names the backup that was taken. Skipped
for files inside .g023/ itself, for brand-new files, and when the content is
unchanged. Disable with G023_WRITE_BACKUP=0, tune retention with
G023_WRITE_BACKUP_KEEP (minimum 1). Covered by tests/test_write_backup.py.
Config scopes — /config
Settings live in two files now: the machine-level config.json next to
K.dat (applies to every project) and, when present, the project's own
.g023/config.json (overrides the machine file for that project only).
/config show both files and which scope is active
/config global promote the current settings to the global default
/config save project pin the current settings to this project
/config save save to the active scope
/config clear drop this project's override; global applies again
/settings marks the persistent keys; test_config_scopes.py holds the
scope precedence to account.
Usage & call accounting
usage.py was rewritten around per-model arithmetic: cache-hit, cache-miss
and output tokens are priced separately (they are priced an order of magnitude
apart), the rates are surge-aware, and when the API omits the hit/miss split
the arithmetic takes the worst-case assumption and says so. The API-call table
in the README — which reads cost 0 calls, which cost 1 — is now asserted by
tests/test_call_accounting.py against a stub client, so the honest numbers
are checked rather than remembered. tests/test_usage_accounting.py covers
the cost arithmetic and the command/handler contract.
Tool registry & schemas split
tools/registry.py now owns permission checks and dispatch to local executors
or subagents; tools/schemas.py owns the wire schemas — including the entire
web-search integration, which is still the one line {"type": "web_search"}
marker appended to the tool list, executed server-side by DeepSeek.
subagents/searcher.py formalises the local, metadata-first grep (pure local
Python — zero API calls).
Documentation & media
The docs were split one page per part (api.md, cache.md, cli.md,
commands.md, config.md, data_files.md, ollama_client.md,
openrouter_client.md, surge.md, tests.md, usage.md, plus the existing
pages) with an index in docs/README.md and a keep-alive map in
READ_1ST_CHANGES.txt.
The screenshot set was re-shot on 1.3.3 — nineteen frames covering the banner,
the command panels, a full read-only agent turn, a file edit with the new
backup line, and the 1.3.3 panels (/signals, /surge, /or, /config).
The captures use sanitised paths (/tmp/g023-shoot/...), so no frame exposes
a real home directory, user name, or API key.
What changed in 1.3.2 (since 1.3.1)
/goalis no longer bounded by the step cap — it sets
max_iterationstoUNLIMITED_ITERATIONSfor the duration of its turn
(alongside the max reasoning effort it already forced), restoring the
previous value in the samefinallythat restores effort and/thinking.- The default step cap is 255, up from 100 — where
/steps default
restores and/help stepsquotes; the shippedconfig.jsoncarries it.
What changed in 1.3.0 / 1.3.1 (since 1.2.0)
- A configurable per-turn step cap (
/steps [n|off|default]), with a
progress line every 10 steps and Ctrl-C as the escape hatch. - An output budget dial (
/max-tokens [n|off|default]). - Symbol-to-line-range file reading: every Python read returns
symbols: {name -> [start_line, end_line]}from the AST walk, decorators
included, so escalation to verbatim source is one targetedReadFilewith
exact line numbers — zero API calls. - Drift signals (
/signals, alias/drift): prefix cache hit-rate
compared against its own history, unrecognised response item types, and
unexplained empty responses — the three cheapest observations that would
move first, stored per day in the SQLite cache so the baseline survives
restarts. - An honesty pass removing unverified claims from the docs.
What changed in 1.2.0 (still current)
- Moved entirely to the DeepSeek Responses API (
POST /responses), which
is what makes DeepSeek's native web search a first-class tool of the
loop rather than a provider bolted on the side — no client executor, no key
to supply, no/websearchcommand. - Response items are echoed back byte-identical (message, reasoning,
web_search_call,function_call/function_call_outputpairs), and
compaction/truncation/error recovery repair pairing before the next request
— afunction_callwith no matching output is a hard 400 in either
direction. - Subagent-first delegation with an SQLite cache: repeated reads of unchanged
bytes are local lookups.
Install
Requirements: Python 3.11+ and a DeepSeek API key.
Drop the folder anywhere and run the installer inside it:
cd /path/to/g023-code
./installer.sh # Windows: installer.batIt finds a Python 3.11+, builds a .venv, installs only missing
dependencies, asks once for the API key, writes a default config.json, and
puts g023 on your PATH. Re-running it is safe and repairs a half-finished
setup. Manual install is pip install -r requirements.txt, the key on the
first line of K.dat, then g023.sh (or g023.bat) from a project folder.
Optional extras: pillow (vision preprocessing), curl_cffi + h2 +
brotli + zstandard (browser-grade fetching); prompt_toolkit is strongly
recommended for tab completion, history and the live status bar but the input
line degrades to a plain prompt without it.
Contents
g023_code/ the package
api.py DeepSeek Responses API client
cli.py the CLI class, main loop, slash handlers
commands.py the command catalogue as data
config.py paths, settings, scopes, pricing data
ollama_client.py Ollama daemon client
openrouter_client.py OpenRouter client (vision)
orchestrator.py the agent loop
prompt.py input line and pickers
signals.py drift signals
surge.py peak/off-peak pricing arithmetic
ui.py theme, glyphs, gauges, traces
usage.py token/cost accounting
web_fetch.py FetchUrl
subagents/ file_reader, searcher, vision, router
tools/ registry (permissions) + schemas (wire shapes)
tests/ pytest suite (147 tests, no network)
docs/ one page per part, indexed by docs/README.md
media/ screenshots (sanitised) + capture tooling
installer.sh/.bat installers
g023.sh/.bat launchers
ds_pricing.json DeepSeek price sheet (regular + surge)
ds_times.json DeepSeek peak windows
K.dat.example key file template (create K.dat from it)
config.json default configuration
What's included
Source, tests, documentation, installers and the screenshot set. Not
included: any API key (K.dat, OK.dat are never shipped), the local
OR_VISION.json, cache/history files, or the media videos.
Requirements
rich, httpx, tiktoken, pygments, prompt_toolkit (recommended),
pillow (vision), curl_cffi/h2/brotli/zstandard (fetching) — see
requirements.txt.
Notes
Costs shown are computed locally from the token counts the API returns and
the price table in ds_pricing.json / SPEC.md §3.2 — an estimate of your
bill, not a reading of it. The prices are surge-aware as of the sheet's
effective date; if DeepSeek changes its rate card, update the JSON.
Verify the archives with SHA256SUMS in this folder.