Oliver VieBrooks

6diss / 6diss and Claude

Contents

Integrating 6diss with Claude

Step by step, two ways — and they are meant to be used together:

A is for the twenty seconds you would otherwise spend reading a loop. B is for the afternoon.

Both assume Claude Code is reading an export. It does not have to: 6diss listens on a Unix socket, so Claude Code can read the listing as the window is drawing it and apply names straight into the open project — one undo step, redrawn under your caret, nothing saved until you say so. See the control channel, and Step 3 below for where it fits.

And a third way, which is B without the second window: C. Claude Code inside 6diss — the whole CLI, hosted as a subprocess and drawn in a tab beside the listing.


A. The assistant inside 6diss

Step 1 — give it a credential

Three ways, best first:

1. ant auth login. The Anthropic CLI writes a credential to ~/.config/anthropic/credentials, and 6diss finds it with no configuration at all — leave the key box in the settings dialog empty. Nothing lands in a 6diss file, and one login serves every tool on the machine.

ant auth login

2. An environment variable. ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN) is picked up the same way:

export ANTHROPIC_API_KEY=sk-ant-...

The catch is where you set it. A desktop launcher does not read your interactive shell's .bashrc, so a 6diss started from the Cinnamon menu will not see a key exported there — put it in ~/.profile (read at login), or use option 1, or option 3.

3. Paste it into the dialog. Assistant ▸ Provider settings ▸ API key. It is written to ~/.config/6diss/settings.json in plain text, which is why it is third.

Step 2 — point 6diss at Claude

Assistant ▸ Provider settings:

Field
Provider Anthropic
API key leave blank unless you chose option 3
Model claude-opus-5 (the default)
Reasoning effort low / medium / high / max — high is the default

Effort is the cost dial. Naming an obvious loop does not need max; working out what a compressed jump table is indexing does. Adaptive thinking is on either way — deciding what a block of 6502 does is the sort of question that benefits from it.

Step 3 — check it took

Open the Assistant tab in the inspector. The top line reads:

Anthropic (claude-opus-5)

If it says — not configured (no API key found), none of the three credential routes found anything; go back to step 1. If it says No provider configured, the dialog was cancelled or Provider is still None.

Step 4 — the first pass

  1. Open a file and put the caret in a routine — or select a range.
  2. Ctrl+I (Assistant ▸ Analyse selection). A caret on a single line is widened to the enclosing region, so "explain this" means "explain this routine" rather than "explain this lda".
  3. The Assistant tab fills with a prose summary and a checklist: proposed labels, comments, region re-classifications and entry points, each with the reasoning that produced it.
  4. Untick anything wrong. Apply ticked suggestions.
  5. Ctrl+Z takes the whole application back as one step.

What lands in the project is tagged as machine-written: assistant labels are shown in teal in the Labels list, assistant comments are prefixed [ai] in the listing. Six months later you can still tell what you worked out from what a model suggested.

Step 5 — the whole-file data pass

Assistant ▸ Classify unknown data sends every still-unclassified run in the file with a hex sample of each (the head of every run, plus the tail of the long ones, up to 24 runs) and asks what they are. This is the pass to run after Ctrl+T (the local detector) has taken the easy ones — sizes and alignments are evidence a heuristic uses well, but "this is a SID player's frequency table" needs to have seen a SID player before.

Step 6 — ask it something

Assistant ▸ Ask a question takes free-form text and gives prose back, with the same listing window attached. "What is the table at $2000 indexed by?" "Why does this write $3B to $D011 twice?" Nothing to apply — it goes in the summary pane.

What actually gets sent

Worth knowing before you point it at someone's unreleased disk:

Nothing else. Other files' contents, the disk image, and the rest of the project stay on the machine.

When it declines

Reverse engineering sits close enough to what safety classifiers watch that a request is occasionally refused outright. 6diss reports that as "The model declined this request" with whatever explanation came back, rather than as an error. Re-asking about a narrower range, or asking what the code does rather than how to defeat it, usually gets through.

Instead of Claude: a local model

Provider ▸ Local talks to anything with an OpenAI-compatible endpoint — LM Studio (http://localhost:1234/v1), Ollama (:11434/v1), llama.cpp, vLLM. List models from this endpoint proves the connection before you spend an analysis on finding out it was wrong. Nothing leaves the machine. Expect to untick more.


B. Claude Code beside 6diss

The assistant answers questions about a window of listing. Claude Code can read the whole project, run the assembler, drive an emulator, and write files. The bridge between them is the export.

Step 1 — export the project as source

File ▸ Export project as 6asm source…, pick a directory, and choose Readable (the byte-identical mode's .byte escapes are for verifying a rebuild, not for reading). You get:

LOADER.asm             one per binary
MAIN.asm
MAIN.exports.asm       generated, for cross-file labels
MUSIC.bas              a file marked "disassemble as BASIC source"
c64.equates.asm        every hardware name the disassembly used
build.sh               reassembles the lot

Step 2 — point Claude Code at it

cd /path/to/the/export
claude

Everything it needs to reason is in the text: runtime addresses in the comments, hardware named, cross-file references as MAIN__init. Useful opening asks:

Ask for the answer in a shape you can act on. Two columns of address and name is thirty seconds of typing back into 6diss; four paragraphs of prose is not.

Step 3 — get the answers back into the project

Four routes, cheapest first.

Over the control channel. The best one, and the reason the other three are shorter than they were. 6dcli --live rename MAIN '$c000=irq_handler:raster split at $30' … applies a whole batch into the running window as a single undo step, with the project open in front of you. Nothing is written to disk, nothing races your next Ctrl+S, and a batch you dislike is one Ctrl+Z. See control-channel.md.

By hand. For a dozen names: Ctrl+G the address, N, type the name. Fast enough that anything more elaborate is procrastination.

Through the assistant. Paste Claude Code's reasoning into Assistant ▸ Ask a question as context for a narrower ask, and take the checklist. You get the review UI and the single-step undo for free.

By editing the project file. A .6diss is one JSON file — deliberately, so it is diffable and hand-editable. Labels and comments are plain arrays:

{
  "items": [{
    "module": "MAIN",
    "loadAddress": 49152,
    "data": "…base64…",              // the bytes; leave alone
    "labels": [
      { "address": 49152, "name": "irq_handler", "role": "Sub",
        "origin": "Assistant", "exported": true, "comment": "raster split at $30" }
    ],
    "annotations": [
      { "address": 49155, "text": "acknowledge the raster IRQ", "inline": true,
        "fromAssistant": true }
    ],
    "regions": [
      { "start": 51200, "end": 51711, "kind": "Charset" }
    ],
    "entryPoints": [49152],
    "breaks": [51712]
  }]
}

Addresses are decimal in the file and hex in the UI. role is Sub / Loc / Data; origin is Auto / User / Assistant — write Assistant for anything a model produced, and Auto labels are the ones a re-trace is free to throw away. kind is any of the region kinds in the manual.

Two rules: close the project in 6diss first (it writes the whole file on save and will overwrite you), and keep a copy — there is no undo across a hand edit. Both are reasons to reach for the control channel instead, which has neither problem.

Step 4 — and then check you were right

Static reading is a hypothesis. build.sh reassembles the export and cmps it against the original bytes, which proves the disassembly is complete; running it proves the reading was correct. If you have the VICE MCP server wired into Claude Code, the last step of a session is usually "set a breakpoint at irq_handler and tell me what the registers are when it fires" — and a label that turns out to be wrong is one M and one N away from being right.


C. Claude Code inside 6diss

Assistant ▸ Claude Code in a tab. The same Claude Code as B — your account, your MCP servers, your skills, bash and all — running as a child process of 6diss and drawn in the editor tab strip beside the listing. No second window, no export to point it at, and the 6diss MCP tools reach the window it is being read in: a name it applies lands in the listing under your caret as one undo step.

What you need

Claude Code itself, found in this order: the ClaudeBinary setting, claude on PATH, ~/.claude/local/claude, then the self-contained binary the VS Code extension unpacks. On a machine with the extension installed, that is nothing to do.

6diss-mcp on PATH, or beside 6diss. Without it the tab still works, but the conversation cannot see the project; it says so at the top of the transcript rather than finding out the hard way.

Settings

Assistant ▸ Provider settings has a Claude Code section at the bottom, separate from the provider above it because the two share nothing:

Claude Code executable blank finds it automatically; the line underneath says which one it found and its version
Model for the tab blank leaves whatever your Claude Code is already set to — opus, sonnet, haiku, or a full model id
Permissions manual (asks in the tab), acceptEdits, plan, auto, bypassPermissions

There is no API key here, and the tab never asks for one. It runs the CLI on your own Claude Code login — the same subscription, MCP servers and skills you get in a terminal. The API key in the section above belongs to the in-window assistant (A), which is a different thing entirely.

Which is worth saying because of the number after each turn. The CLI reports total_cost_usd on every turn whether or not anything is being billed; on a subscription it is what those tokens would have cost at API list price. 6diss shows tokens instead, and only prints a dollar figure when the session really is running on an API key.

How it behaves

json { "ClaudeExtraMcpServers": ["vice", "goattracker"] }

Set "ClaudeStrictMcp": false to go back to the CLI's own idea of which servers exist. Either way the header note in the transcript says which ones it ended up with. Skills, CLAUDE.md and your permission rules are always your own — only the server list is narrowed. - It zooms. Ctrl+wheel over the transcript, or Ctrl +/- with the tab in front — the same chords the listing uses, acting on whatever you are looking at, and Ctrl+0 puts it back. It scales rather than resets to one size, so the ladder that separates Claude's prose from tool calls from tool output survives. The zoom sticks between sessions. - Nothing is saved until you save it. Same as every other route into the project: edits land in the open window, Ctrl+Z takes them back, Ctrl+S is still yours to press.

Worth asking it

Anything you would ask in a terminal, plus the window:

Where the findings go

Labels and comments hold conclusions; they cannot hold reasoning. "The record is 0x244 bytes, the first fifteen are the name in PETSCII, and the two saved games disagree about byte +$1C" does not fit in a label, and before there was anywhere to put it, it went into the conversation and left with it.

It now goes in a note — a real .md file in <project>.docs/ beside the project, listed under Notes in the tree and opened in a tab beside the listing. Four tools:

list_docs every note, with its path — worth calling early, a previous session may have written down the thing you are about to spend an hour on
read_doc one note, including unsaved edits in the tab
write_doc write or append to one, creating it if there is none of that name
open_doc put it in front of the user, because "I wrote it up" is not the same as showing them

Two things follow from the notes being ordinary files. The tab watches its file, so a note appears as it is written rather than when the conversation ends — worth an open_doc before a long write-up. And a session with file tools can read and edit the .md directly instead; the paths in list_docs are there for that. What the MCP tools add is the window: a write through them lands in the open tab and in the tree straight away.

Hex addresses in a note are drawn as links the user can click to put the listing on them, so write $9e40 rather than "the table at 9e40". Notes are the one thing here that Ctrl+Z does not take back — they are files, not project decisions.

What it is not, yet

A plain transcript: no markdown, no folded tool output, no diffs. The conversation is inside 6diss with its permissions intact, which was the hard part.


Which one, when

Assistant in 6diss Claude Code beside Claude Code inside
One routine, right now ✅ ✅
"What is all this data?" ✅ (whole-file pass) ✅ ✅
Reasoning across every file on the disk ✅ ✅
Reading the code and the emulator ✅ ✅
Reviewable, one-click undo ✅ ✅ (control channel) ✅
Editing files, running builds ✅ ✅
Without leaving the window ✅ ✅
A terminal you can pipe and script ✅

The design rule is the same either way, and it is worth stating plainly: the model is a fast second reader, not an authority. Everything it proposes arrives as something to accept or reject, tagged with where it came from, and one Ctrl+Z from gone.