Skip to content

Releases: g023/g023code

g023 Code 1.3.4

Choose a tag to compare

@g023 g023 released this 14 Sep 21:57
1371132

g023 Code — Release 1.3.4

Version: 1.3.4
Date: 2026-09-14
Supersedes: 1.3.2 (and the earlier 1.3.3 cut of 2026-08-21)
Artifacts: g023-code-1.3.4.tar.gz, g023-code-1.3.4.zip, unpacked tree in g023-code-1.3.4/

Pure-Python DeepSeek V4 powered coding agent. Subagent-First architecture,
terminal-native UI built on rich + prompt_toolkit. One model, one
endpoint: deepseek-flash on POST /responses. 421 tests, all
passing, none of them on the network.

This recut replaces the 2026-08-21 1.3.3 artifacts. Those archives
shipped deepseek-v4-flash, tiktoken, a 147-test suite, and a
partial installer config.json. The program in this folder is the
current one.

1.3.4 (2026-09-14 recut)

The theme is still money — knowing what the API costs before, while,
and after you spend it — plus everything measured since the August cut
about how that money actually moves.

Model identity — deepseek-flash

Every DeepSeek call sends deepseek-flash: orchestrator, FileReader's
LLM path, nested Agent, /g023-compact, DeepSeek vision. /model
accepts the alias flash. Retired ids (deepseek-v4-flash,
deepseek-v4-flash-vision-exp) coerce on load. deepseek-v4-pro is
still withheld: /responses has not enabled it.

Thinking is a 0–100 dial, default and ceiling 75 (wire high).
max / 100 / xhigh cap to 75. Off is reasoning: {"effort": "none"}.

What we measured (2026-09-10 sheet, 2026-09-14 probes)

Pinned by tests or the published sheet; the rest is labelled.

  • Off-peak Flash: hit $0.003/M, miss $0.15/M (~50×), output
    $0.60/M (~200× a hit). Peak is exactly 2×, Monday–Friday only.
    Weekend hours that look like Beijing 09–12 / 14–18 are off-peak.
  • Keeping a hot prefix beats shrinking it. DeepSeek hits only on a
    full prefix-unit match from token 0. Blanking 500 cached tokens busts
    a ~3k tail; recoup is ~294 further turns. cost_policy.py therefore
    does not rewrite a cached prefix unless the window is full, the
    leftover is uncached, or the objective is done. Layer-1 auto-micro
    waits for window pressure. Bulky Bash / FetchUrl / ListDir bodies are
    vaulted before they enter a cache unit.
  • FileReader buys Flash only for a semantic question. Unfocused
    reads of any language are a local index. An exact / unique-suffix
    symbol focus is local too (0 API). A sentence still costs 1.
  • Nested Agent reuses the parent's frozen prefix (instructions +
    tools + pinned effort). Depth-2 was measured and not shipped.
  • Rejected with numbers: sharing the parent prefix for focused
    FileReader; slicing ReadFile / Agent JSON at 6000 chars (a 10505-char
    summary became an unparseable 5590-char stump).
  • Effort and temperature are pinned to the standing prefix — both are
    /responses cache-key fields.

End-to-end session cost is still not measured. G023_READFILE_RAW=1
is the A/B flag; /cost is the meter.

Installer

installer.sh / installer.bat write the full PERSISTED_KEYS set
matching Settings defaults: deepseek-flash, reasoning_effort: 75,
max_iterations: 255, max_context_tokens: 256000,
vision_backend: none, vision_max_image_dim: 800, backups on, surge
notify on / pause off. tiktoken is gone — the context gauge is last
API input_tokens / settings.max_context_tokens. Re-running is still
the way to repair a half-finished setup.

New since the August 1.3.3 cut (now 1.3.4)

  • cost_policy.py — cache-aware keep vs compact vs vault.
  • effort.py — 0–100 ↔ wire aliases, [handoff] / [next_effort].
  • learn.py — cross-session procedures (/learn, Learn* tools).
    Guides are searched on demand, never prepended to the system prompt.
  • session_log.py — append-only JSONL + .g023/logs/ handoffs.
    /resume and --continue / /resume log.
  • working_set.py — remaining-work object; goal-completion judge.
  • memory_notes.py, prompt_store.py — .g023/memory/,
    .g023/prompts/ (Ctrl+Up).
  • paths.py — project-root confinement for file tools and /undo.
  • project_instructions.py — g023.md / g023_compact.md /
    AGENTS.md.
  • or_subagents.py — /orsub OpenRouter offload for Agent turns.
  • Tools: Edit (unique-span replace, fails closed), Glob, TodoWrite,
    LearnSearch/Get/Put, SessionSearch.
  • /max-ctx, /compact-threshold, /undo, /g023-compact.
  • WriteFile and Edit snapshot .g023/backups/ before overwriting.
  • Vision send is always constrained-resized to 800px.
  • Parallel ALLOW reads; pairing-intact history is a hard invariant.

Surge, OpenRouter vision, config scopes (from the August cut, still here)

/surge converts Beijing peak windows to the local clock, prices with
them, and can pause around them. /or is OpenRouter vision (OK.dat).
/config is the global vs per-project split. /signals (alias
/drift) is the cheap view of silent API drift.

Documentation & media

Docs are one page per part, indexed by docs/README.md, audited
against this source. The README's API-call table, price numbers, and
"what we measured" claims are either asserted by a test, quoted from
the 2026-09-10 sheet, or labelled as arithmetic / unmeasured.

Screenshots were re-shot on this build from /tmp/g023-shoot/...
(sanitised paths, no home directory, no keys, deepseek-flash only).
A /responses probe timed out, so live agent-turn stills and videos
were not rebuilt; panel stills do not need the API and are current.

What changed in 1.3.2 (since 1.3.1)

  • /goal is no longer bounded by the step cap.
  • The default step cap is 255, up from 100.

What changed in 1.3.0 / 1.3.1 (since 1.2.0)

  • Configurable per-turn step cap and output budget dial.
  • Symbol-to-line-range file reading.
  • Drift signals (/signals).
  • 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. Response items are echoed back byte-identical.

Install

Requirements: Python 3.11+ and a DeepSeek API key.

cd /path/to/g023-code
./installer.sh          # Windows: installer.bat

It 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.

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
  cost_policy.py      cache-aware keep vs compact vs vault
  effort.py           0–100 effort ↔ wire aliases
  learn.py            cross-session procedures
  orchestrator.py     the agent loop
  paths.py            project-root confinement
  session_log.py      JSONL + objective handoffs
  surge.py            peak/off-peak pricing arithmetic
  usage.py            token/cost accounting
  working_set.py      remaining work + goal judge
  subagents/          file_reader, searcher, vision, router
  tools/              registry (permissions) + schemas (wire shapes)
docs/                 one page per part, indexed by docs/README.md
media/screenshots/    sanitised TUI captures (no home path, no keys)
installer.sh/.bat     installers
g023.sh/.bat          launchers
ds_pricing.json       DeepSeek price sheet (regular + surge)
ds_times.json         DeepSeek peak windows (Mon–Fri)
K.dat.example         key file template (create K.dat from it)
config.json           default configuration (Settings defaults)

What's included

Runtime source, user documentation, installers, launchers, the price
sheet, and the screenshot set. Not included: tests, capture
tooling, videos, build notes (SPEC.md, bbs/, scratch/,
memory/), API keys (K.dat, OK.dat are never shipped),
OR_VISION.json / OR_SUB_MODELS.json (optional; the program runs
without them), cache/history files.

Requirements

rich, httpx, pygments, prompt_toolkit (recommended), pillow
(vision), curl_cffi/h2/brotli/zstandard (fetching) — see
requirements.txt. No local tokenizer.

Notes

Costs shown are computed locally from the token counts the API returns
and the price table in ds_pricing.json — an estimate of your bill,
not a reading of it. The prices are surge-aware as of the sheet's
effective date (2026-09-10); if DeepSeek changes its rate card, update
the JSON.

Verify the archives with SHA256SUMS in this folder.

g023 Code 1.3.3

Choose a tag to compare

@g023 g023 released this 21 Aug 22:21
b2af2d1

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.json anchors 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. /cost and the status bar split regular vs surge
    (2×) rates per model, straight from ds_pricing.json — so the number you
    see during a peak hour is the peak number, not a stale off-peak estimate.
    The status bar shows SURGE 2× while a peak window is active.
  • It can pause for them. /surge on stops 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 new openrouter_client.py talks to OpenRouter using
    the OK.dat key. Models come from ./OR_VISION.json (project folder) in
    priority order; when one returns HTTP 429 the next on the list is tried.
    Default model google/gemma-4-26b-a4b-it:free. Free :free models are
    capped at 50 requests/24h for accounts under $10 of lifetime credits, and
    up to 1000/24h after that — /or tier free|credits tells g023 which
    ceiling you are on, and /or shows today's usage against it.
  • deepseek — DeepSeek's own experimental multimodal model,
    deepseek-v4-flash-vision-exp, billed on the same K.dat key at exactly
    the token rates of deepseek-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)

  • /goal is no longer bounded by the step cap — it sets
    max_iterations to UNLIMITED_ITERATIONS for the duration of its turn
    (alongside the max reasoning effort it already forced), restoring the
    previous value in the same finally that restores effort and /thinking.
  • The default step cap is 255, up from 100 — where /steps default
    restores and /help steps quotes; the shipped config.json carries 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 targeted ReadFile with
    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 /websearch command.
  • Response items are echoed back byte-identical (message, reasoning,
    web_search_call, function_call/function_call_output pairs), and
    compaction/truncation/error recovery repair pairing before the next request
    — a function_call with 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.bat

It 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 CL...
Read more