kimicode

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package kimicode implements an event-level adapter for Kimi Code (MoonshotAI/kimi-code, MIT). Kimi Code keeps one append-only wire log per AGENT per session:

<home>/sessions/<workspace>/<session>/agents/<agent>/wire.jsonl

The log is a mixed record stream (prompts, messages, loop events, config). Exactly two record types matter here: `llm.request`, written before every provider call, and `usage.record`, written after one returns.

THE MODEL TRAP. `usage.record` carries a `model` field and it is NOT a model id: kimi records usage as `usage.record(request.modelAlias, ...)`, so the field holds the CONFIG ALIAS the profile was bound under — observed here as the literal `__kimi_env_model__`, the synthetic alias for an environment-configured profile. The real model id appears only on the `llm.request` record that preceded the call, which carries BOTH (`model`: `gemma4:31b-cloud`, `modelAlias`: `__kimi_env_model__`). Every usage record is therefore resolved against the nearest PRIOR request in the same file, and the carry-forward survives a tail read in the checkpoint. Taking the record's own field would file every session on this machine under one unpriceable pseudo-model.

THE DOUBLE-COUNT TRAP. The same token counts appear TWICE in the file: once as `usage.record`, and once inside the `context.append_loop_event` whose `event.type` is `step.end` (which also carries the provider `messageId`). They are one API response reported by two writers, not two calls. Only `usage.record` is read, because it is the complete stream — a compaction or title call records usage with `usageScope: "session"` and no loop step at all — and because counting both would exactly double every loop turn.

SCOPE IS NOT CUMULATIVE. `usageScope` is `"turn"` or `"session"` and both are per-request DELTAS: kimi's own replayer folds every record with `addUsage(byScope[scope], rec.usage)` and `addUsage(byModel[model], rec.usage)`, i.e. it SUMS them. Every record is counted once, whatever its scope; filtering by scope would drop the compaction and summarisation calls that only ever arrive as `"session"`.

PRIVACY. The wire log is full of content — system prompts, user input, message parts, tool arguments, tool schemas. None of it is decoded: the line struct names only counters, model ids, times and scopes, so encoding/json discards every other key as it parses and the content never becomes a value in this process. No raw audit payload is built either, so `privacy.no_raw` is satisfied by construction rather than by a switch.

Index

Constants

View Source
const DataDirEnv = "KIMI_CODE_DATA_DIR"

DataDirEnv is a second, lower-precedence root override.

HONEST CAVEAT: kimi-code 0.36.1 does NOT read this variable — the bundle carries `KIMI_CODE_DATA_DIR_NAME`, a constant holding the string ".kimi-code", and no `process.env.KIMI_CODE_DATA_DIR` lookup anywhere. It is accepted here as an explicit operator override for installs that place the tree elsewhere, and it is exported so the supervision guard accounts for it like any other discovery variable. KIMI_DATA_DIR (the Kimi CLI variable named by ccusage) is deliberately NOT read: it belongs to the older, separate product and moves a tree this adapter does not parse.

View Source
const HomeEnv = "KIMI_CODE_HOME"

HomeEnv names the environment variable that moves the Kimi Code data root, and with it every session this adapter reads. Verified against the installed CLI (@moonshot-ai/kimi-code 0.36.1): `getDataDir()` returns `process.env.KIMI_CODE_HOME` when set and `~/.kimi-code` otherwise, and it is the ONLY variable that moves the sessions tree.

Exported for the same reason claudecode.ConfigDirEnv is: what gets collected is decided here, not by the defaults, and a systemd unit does not inherit the installing shell's environment.

Variables

This section is empty.

Functions

func New

func New() adapter.Adapter

New returns a Kimi Code adapter.

Types

type Adapter

type Adapter struct{}

Adapter reads Kimi Code session wire logs. Read-only.

func (Adapter) Capabilities

func (Adapter) Capabilities() model.ToolCapability

Capabilities declares what this project can say about Kimi Code.

Cost is COMPUTED: nothing here calls SetCost. There is NO activity at all — this adapter references model.ActivityEvent nowhere, so its surface exposes usage and nothing else.

func (Adapter) Collect

func (a Adapter) Collect(ctx context.Context, src adapter.Source) (adapter.Observation, error)

Collect reads one wire log in full and returns its usage events.

func (Adapter) CollectIncremental

func (a Adapter) CollectIncremental(ctx context.Context, src adapter.Source, cp *model.SourceCheckpoint) (adapter.Observation, error)

CollectIncremental reads only what is new since cp: an unchanged size+mtime skips the file entirely; growth tail-reads from the stored offset with the persisted model carry-forward; any shrink or same-size rewrite re-reads from zero. Kimi does rewrite a wire log in place — a forked session is truncated at a turn, and a wire-protocol migration rewrites the whole file — so the shrink path is real, not theoretical; re-derived dedup keys collapse in the store. A nil cp is a full read.

func (Adapter) Discover

func (a Adapter) Discover(ctx context.Context, cfg adapter.DiscoverConfig) ([]adapter.Source, error)

Discover locates every agent wire log under each root. The tree is <root>/sessions/<workspace>/<session>/agents/<agent>/wire.jsonl, and SUBAGENTS get their own directory beside `main` — each agent owns its own recorder, so a scan restricted to `main` would drop every subagent's tokens.

func (Adapter) DisplayName

func (Adapter) DisplayName() string

DisplayName returns the human-friendly name.

func (Adapter) ID

func (Adapter) ID() string

ID returns the stable tool identifier.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL