Oliver VieBrooks

6diss / 6dcli

Contents

6dcli — reading and editing a .6diss from a script

6dcli is the console front end, in the 6diss download. What it prints is the listing the GUI draws, from the same disassembler, with the same knowledgebase annotations and the same cross-file xrefs.

It exists for the round trip in Claude integration, Step 3: read a file the way the window reads it, reason about it somewhere else, write the answers back without hand-editing JSON.

Reach for --live first. With it, every command below goes to a running 6diss over the control channel instead of to a file — same verbs, no project argument, and the answers include everything not yet saved. This page is the file-based half: for when nothing is running, or when the project is not the one that is open.

Commands

6dcli files <project> every binary: module, name, address range, label count, packer, notes
6dcli list <project> <module> [--from $2dc8] [--to $2e40] [--plain] the rendered listing
6dcli labels <project> <module> [--from …] [--to …] [--user] labels, --user hides the Auto ones
6dcli xrefs <project> <module> <addr> what reaches an address, from this file and from the others
6dcli bytes <project> <module> <addr> [--len 64] hex + ASCII
6dcli rename <project> <module> <addr>=<name>[:comment] … set labels
6dcli comment <project> <module> <addr>=<text> … set annotations
6dcli docs <project> the project's notes: title, file, size, first line
6dcli doc <project> <title> print one note
6dcli write-doc <project> <title> [--append] [--text …] write one; text comes from stdin unless --text is given

Addresses are hex, with or without $. rename takes --role sub\|loc\|data and --origin user\|assistant; comment takes --block for a line above rather than beside.

files also takes --pattern 'MON*' and --summary. On a project with more than about fifty files, start with --summary: it groups by name family and reports how many of each, what sizes they come in and where they load, which is the shape of the release. The list of eight hundred names is the least useful true thing 6diss can say about it.

Answers onto disk, and the analyses

These work against the file with no window running.

dump <project> <module> <out.lst> [--from …] [--to …] [--plain] the listing, as a file you can grep
dump <project> <module> <out.bin> --bytes [--from …] an address range, as raw bytes
dump <project> --all --directory <dir> [--pattern …] [--header] every file's image, plus a manifest.tsv of load addresses
decode <project> <module> [<addr>] [--kind …] [--stride N] a table's values — pointer targets, strings, a jump table's 32 destinations
variance <project> <glob> [--varying-only] which byte offsets carry information, across a family
variance <project> <module> --stride 480 the same, over the records inside one file
compare <project> <module> <other> [--stride N] equal, or exactly which offsets differ
compare <project> --all [--pattern …] which files are really the same file — and which names carry two different builds
graph <project> <module> [--calls-only] control-flow targets with caller counts
graph <project> <module> --touched write --from '$d000' --to '$dfff' every address the code reads or writes
pointers <project> <module> --strings-from '$9400' find a pointer table nobody declared
pointers <project> <module> --validate '$9658' does the table you declared actually land?
registers <project> <module> [--from …] [--known-only] what A, X and Y hold at each instruction
run <project> <module> [--entry …] [--a N] [--write-to f.bin] execute it, and report what changed

run is not a C64 — no VIC, no SID, no interrupts, $D000-$DFFF is plain RAM. It runs a routine against a snapshot of the project's memory and tells you what it wrote. Everything that needs a real machine still needs VICE, and that is a boundary rather than a shortfall.

dump --all deserves a note. A project imported from eight disk sides already holds every byte; re-extracting them from the D64s to run a format decoder over them is doing work 6diss has already done, and it throws away the load addresses the project worked out. The manifest carries those.

--live only

The rest of the menu needs a window to run it in — an undo stack, a listing to redraw, and a user watching — so these exist under --live and nowhere else:

load-address <module> <addr> [--header 2] [--embedded] where the file really runs; everything moves with the bytes
describe <module> [--description …] [--notes …] [--module-name …] [--tool ecl\|--no-tool] the banner at the top of the file, and which tool renders it
same-file <module> [<original>] [--clear] that file is this file: borrow its recipe instead of writing a second one
same-file --all [--pattern …] pair up every byte-identical file at once, and report the names carrying two builds
invoke [<command>] / screenshot <out.png> / measure [<control>] the window itself, for working on 6diss
define <module> <addr> <name>[:comment] [--scope file\|owner\|project] name an address the file refers to
constant <module> <value> <name> [--scope project\|file\|instruction] [--site …] name a value; $1b is hex, 27 is decimal
move-label <module> <to> [--from …] put a label on the byte it belongs to
address-load <module> <target> --low … --high … [--name …] the two immediates that are halves of one address
overlay <module> <start> <end> <exec> [--kind DriveCode] this block runs somewhere else
ref <module> <target-module> [--site …\|--from …\|--file] which file a reference means; "" for none
split <module> <addr> … / --path f.txt / --every N / --clear where a line starts inside a table; a list is one call and one undo step
retrace <module> re-trace from the entry points
find-code, detect, brain <module> [--apply] [--accept 0,3,7] propose, then accept what you believe
players <module> [--apply] which playroutine is in here
depack <module> --from … --to … [--apply] ask 6crunch about a range
regions <module> what has been classified, and the overlays
find <text> [--project] [--bytes] [--match-case] text, names, operands or a9 ?? 8d 20 d0
export <directory> [--exact] 6asm source; --exact writes a build.sh that compares
render <module> <out.png> [--kind Charset] [--from …] a charset, sprites or a bitmap as a picture
source-tool [--match 'ECL??'] [--tool ecl] [--command …] [--input prg\|raw] [--comment ';'] [--clear] render a file with a tool that isn't 6diss

find-code, detect and brain print an indexed proposal list and apply nothing. Read it, then run the same command with --apply --accept 0,3,7. That is the review dialog the window opens, kept rather than dropped.

Any <module> above also accepts a glob. region 'MON*' $7c00 $7c0f TextAscii is one decision, so it is one call and one Ctrl+Z rather than sixty-nine of each. The undo depth is what makes this matter rather than the process count: the stack is a hundred steps deep, so a sweep applied one step at a time did not merely make undo tedious, it swallowed every step in front of it. rename, comment and split also take --path, so a list a session has just written is a list 6diss can read.

The note commands are exempt from the rule below, because they never touch the .6diss: a note is a .md in <project>.docs/ beside it, and the project reads whatever is in that folder when it opens. Writing one under a running 6diss is safe, and write-doc on a title the project does not know creates the file and says it will be listed the next time the project is opened. To have it appear now, use --live.

The one rule

6diss writes the whole project file when it saves. A write underneath a running 6diss is gone the moment the user hits Ctrl+S. So rename and comment:

If no instance answers — an older build, the channel switched off — nothing is known to be at risk and the write goes ahead. --force overrides the refusal, and still means the user must reopen the project rather than save over it.

Reading a listing without drowning

— unclaimed on a line means "this address is inside several files' ranges and none of them owns it" — noise when the address is RAM that overlays share, which in an overlay-based game is most of it. It used to be worse than noise: the note named every candidate, so on an 820-file project an address touched by 250 of them put 250 file names on every line referring to it, and a 24-instruction routine rendered as about 15,000 tokens. The disassembler now names three and counts the rest, and drops the note entirely past a couple of dozen candidates.

If you still want it gone entirely:

6dcli list game.6diss LIBRARY \
  | sed -E 's/ *; (in|also in) [A-Z_0-9, ]*— unclaimed//; s/ +; TBUFFR\+[0-9]+.*//'

The better answer for a long listing is dump, which writes it to a file — then grep it rather than reading it through a pipe.