Skip to main content

whyline

Use Claude Code and Codex on the same project without either one starting blind.

$ whyline explain src/tsconfig/resolve.ts:41

Decision          Treat only canonical in-repo workspace package exports as internal
Because           node_modules must be readable for resolution but never indexed
Rejected          classify any resolvable node_modules target as internal
                  indexes third-party declarations and violates FR-005
Confidence        High — a recorded decision matches the commit for this line.

Free, Apache-2.0, local-only. No accounts, no telemetry, no paid tier, ever.

The problem this solves

Claude Code and Codex are good at different things. You might want Claude to plan a feature and write the tests, then Codex to review the diff — or the reverse. That combination is genuinely useful, and today it is genuinely painful: the second agent starts from nothing. It has no idea what the first one concluded, what it tried, or what it deliberately ruled out. So you re-explain, or paste, or just give up and use one agent for everything.

whyline fixes that with a decision record both agents write to and read from. The one that finishes leaves behind what it decided and what it rejected; the one that starts picks it up. Neither has to be told twice.

On the subscriptions you already pay for. whyline never touches a credential. It launches the vendor's own CLI with exec, so Claude Code authenticates as Claude Code and Codex authenticates as Codex. No API keys, no per-token billing, nothing metered on top of what you already have.

And because the record is committed to your repository as plain Markdown, it outlives the session. Six months later, whyline explain still answers why a line of code exists — which is the same mechanism, read at a longer horizon.

Install

Not yet published. From a clone:

uv tool install --from . whyline

Zero production dependencies — standard library only. Python 3.11+, plus git.

Quickstart

whyline init                     # scaffold, add instructions, install the hook

Then work normally. Your agents record their own decisions, because init adds an instruction to AGENTS.md asking them to. When you want to switch:

whyline run codex "review the caching change"

That composes what Claude decided and hands the terminal to Codex with it attached. The reverse works the same way: whyline run claude "...".

The rest of the surface:

whyline brief                    # print the handoff context without launching
whyline explain src/a.py:14      # why does this line exist?
whyline note "chose X" --because "Y" --rejected "Z: too slow" --file src/a.py
whyline timeline --file src/a.py
whyline status

How it works

Three layers feed one ledger:

  1. git resolves a line to a commit via git blame. Works before whyline has recorded anything.
  2. A hook silently records sessions, instructions and file edits. It can never fail your session — every path exits 0.
  3. Your agent records the reasoning. whyline init adds an AGENTS.md instruction asking agents to log decisions and rejected alternatives. This is the only layer that captures why.

.whyline/decisions.md is committed and readable with whyline uninstalled. .whyline/ledger.jsonl is gitignored, because it holds your prompt text.

Does the third layer actually work?

It was the design's one unproven assumption, so it was measured before the features depending on it were built. Over three days across two agents on a real project, 19 decisions were recorded across 14 commits — Claude Code 150% of its non-trivial changes, Codex 130%, against a 60% threshold. Every one carried a rationale and a concrete rejected alternative. Codex was never reminded.

Full method and caveats: m0/RESULTS.md.

Honest limitations

  • Switching agents is a relay, not a shared conversation. Vendor CLIs are separate processes with separate context windows. brief hands the next agent a written summary; it cannot continue the previous conversation. Nothing can.
  • explain reports confidence and will say when it does not know. An empty ledger produces an honest empty answer, not a guess. File-level explain never claims high confidence, because without a line there is no blamed commit.
  • The hook is Claude Code only in v1. Codex and Gemini both support hooks, so this is a limit of scope, not of design.
  • Gemini is not supported by run — its free personal tier was withdrawn.
  • Parallel agents are not coordinated. No worktree isolation in v1.
  • brief degrades on a fresh clone. The ledger is gitignored, so a clone has only the committed decisions.md, which carries day precision rather than full timestamps. brief merges both sources and tells you which is which.
  • macOS and Linux are verified; Windows is not. CI passes on ubuntu-latest and macos-latest across Python 3.11 and 3.13. Windows via WSL is untested — a plausible claim, not an observation.

Credentials

whyline never reads, stores, forwards or proxies a vendor token. run replaces itself with the vendor's own CLI via exec, which does its own authentication. Your subscription works because the official CLI is what talks to the vendor. Permission-bypass flags are never added.

Performance

Measured on an M-series Mac, median of seven runs, against a 200 ms target:

Command Total whyline's own cost
brief 41 ms 23 ms
timeline 46 ms 27 ms
status 47 ms 28 ms
explain 79 ms 60 ms

Bare Python interpreter startup is 19 ms of every figure above, so the right-hand column is what whyline actually costs. explain is dearer because it shells out to git blame.

On a 50,000-event, 6.5 MB ledger explain takes ~159 ms against a 1 s target — which is why there is no SQLite index.

Licence

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

whyline-0.1.0.tar.gz (44.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

whyline-0.1.0-py3-none-any.whl (32.8 kB view details)

Uploaded Python 3

File details

Details for the file whyline-0.1.0.tar.gz.

File metadata

  • Download URL: whyline-0.1.0.tar.gz
  • Upload date:
  • Size: 44.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for whyline-0.1.0.tar.gz
Algorithm Hash digest
SHA256 50ffce638e840389f59af0a62d2fb8e9f5bbbf87897b5c7238ddca8ff9233c84
MD5 3f74e3babbeec8ad83c5e30df2730c38
BLAKE2b-256 1bd365e7aa4ad42ea1f698a4292860ce6fe48bb60c3add51765ca325547c7a05

See more details on using hashes here.

File details

Details for the file whyline-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: whyline-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for whyline-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3660c9143c179ba911c2fc2f1a87a9181a58c280bf06d3b78978f15603b2c436
MD5 b9de2af21a2ae7593c98045760d1dcbf
BLAKE2b-256 63c0e3d9a01b91028edb5637091380b0d635ff75ef9df5275b27779da2b9b904

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page