Skip to main content
Glama

c64-kb

A reference for the stock Commodore 64, served to coding agents over MCP and a CLI: hardware, techniques, pitfalls, recipes and toolchains, as markdown pages indexed for search and as a graph.

How the pages are checked:

  • Every code listing is built with the toolchain it names (Oscar64, KickAssembler or cc65) before it lands: npm run check:listings.

  • Every recipe is run headless in VICE at a pinned cycle count, on each model its entry in docs/recipes/runs.json names, and its screenshot is compared pixel for pixel: npm run verify:recipes.

  • A number states its evidence: measured here (VICE, an assembler, the ROM bytes), two independent pages agreeing, arithmetic from stated constants, or unverified.

  • A correction says what the old text claimed.

"Verified" means VICE x64sc 3.10 with the real ROM images, not a C64 on a bench. PAL runs use VICE's default C64C (VIC-II 8565, SID 8580, CIA 8521); -model c64 is the older 6569 machine. Measurements on real hardware are tracked in #9.

Starters

Each starter in templates/ is a small playable game or demo with a title, a game loop, sound and a self-check. Each picture is the normal build in play on PAL.

Make a project from one with npm run new-project -- <starter> <dir> (see Start a game).

Related MCP server: Graph-Mem MCP

Recipes

A selection of recipe screenshots. Each is the committed screenshot of the listing on its page, taken at a pinned cycle count; a run that differs by one pixel fails the gate.

Built from the KB

C64-KB is a five-part demo written from the techniques and recipes above and nothing else, run headless under the harness on PAL and NTSC with a verdict byte, a frame meter and pinned screenshots. Its end screen prints each part's worst and typical frame from the part's own stopwatch, its tune plays from a data image under the KERNAL, and its README lists each part's techniques and figures. The build fed the KB back: the plasma and the luminance dissolve are technique pages with recipes now, and six pitfalls came out of it.

The end screen: five parts, each with its worst and typical cycles, PARTS 5/5 PASS and the frame meter

Quick start

You need Node.js 24.12 or later, Docker, and Ollama with mxbai-embed-large pulled. Ollama is needed to ingest the docs. After that, queries work without it: search falls back to keywords, and the graph tools do not use it.

From npm

npm install -g c64-kb
ollama pull mxbai-embed-large

c64-kb services up        # Qdrant (port 7333) and FalkorDB (7379) in Docker
c64-kb ingest             # builds both stores from the docs in the package; a few minutes
c64-kb health             # checks the services and prints what the stores hold

claude mcp add c64-kb -- c64-kb serve    # connect Claude Code

State goes to $XDG_DATA_HOME/c64-kb, else ~/.local/share/c64-kb. That covers the analytics database, the BM25 vocabulary, ingest hashes and the containers' volumes. Set C64_KB_DATA_DIR to move it. After upgrading, run c64-kb ingest --clean so the stores match the new docs. c64-kb services down stops the containers and keeps their data.

From a clone

A clone is needed for the starters, new-project and the gates, because scripts/ is not in the npm package. The starters and gates also need Oscar64, Java with KickAssembler 5.25, VICE (x64sc and c1541), make, and Python 3 with Pillow. Missing toolchains are reported, not skipped silently.

docker compose up -d      # Qdrant and FalkorDB; volumes in ./storage
npm install
npm run build
npm run ingest            # first time; later runs skip unchanged files
npm run health

In a clone, state lives in ./data. The repo's .mcp.json runs node dist/cli.js serve, so Claude Code opened in the repo connects on its own once dist/ is built.

Example

$ c64-kb check-compatibility fli_image sprite_multiplex_24
# Compatibility: fli_image + sprite_multiplex_24

**Verdict:** INCOMPATIBLE — not as combined; each hard conflict below says how to separate them.
...
## unit_contention (hard): fli_image × sprite_multiplex_24
**Shared:** vic_raster_irq
Both fli_image and sprite_multiplex_24 own vic_raster_irq: each writes or holds it every frame and expects no one else to.
**Resolution:** There is one raster compare. Run both as handlers in one interrupt chain (irq_chain_table): ...
...

VERSION carries the data, schema and tool-surface versions, and CHANGELOG.md says what each change fixed and why.

Other examples: c64-kb technique-lookup sideborder_open, c64-kb pitfalls-for stable_raster_irq, c64-kb plan-budget scroll_panel_split sprite_multiplex_game, c64-kb game-briefing "vertical shooter". c64-kb --help lists every command, and --json gives the structured form.

Connect another project

From an npm install, add this to the project's .mcp.json:

{
  "mcpServers": {
    "c64-kb": { "type": "stdio", "command": "c64-kb", "args": ["serve"] }
  }
}

From a clone, use "command": "node" and "args": ["/absolute/path/to/c64-kb/dist/cli.js", "serve"].

Start a game

In a clone:

npm run new-project -- shmup-vertical ~/Developer/c64/mygame

This copies the starter and the shared harness (templates/_harness/) into the new directory. It writes .mcp.json and local.mk pointing at this checkout, then runs the starter's headless check to prove the copy works. npm run new-project -- --list names the starters: shmup-vertical, platformer, action-puzzle, adventure, beat-em-up, racing, run-and-gun, demo, and two minimal templates that show the harness rather than a game: hello (Oscar64 calling KickAssembler) and hello-kick (KickAssembler only).

In the new project:

Target

What it does

make

Builds, once PLAN.md holds the KB's compatibility and budget output for your technique list (the plan gate)

make run

Opens the game in VICE

make shot check

Runs the autopilot build (a scripted player drives the game) headless on PAL and NTSC and grades the screenshots

make selftest

Proves the check fails on a deliberately broken build

make disk

Builds a .d64

make claims

Traces every store the program makes in VICE and fails on one to hardware it did not declare

make zp

Lists the zero page the compiled C touches

make released OSCAR64_RELEASED=<path>

Builds and grades the game with another Oscar64, such as a release

A frame meter prints each run's worst and median frame in cycles. Several starters add their own proofs, such as a tear check, a disk save-and-reload test or a lost-frame soak. docs/workflow/agent-harness.md explains the loop.

The starters build with the Oscar64 described under Toolchains. shmup-vertical, platformer, action-puzzle, beat-em-up and racing are also recorded passing on the released v1.32.273 (make released).

Tools

The MCP server and the CLI call the same functions.

Look something up

Tool

Answers

c64_search

Hybrid semantic and keyword search across every page

c64_lookup_register

A register by name (D011), mnemonic or address: chip, read/write, aliases

c64_lookup_kernal

A KERNAL routine by name or jump-table address, with its paired routines

c64_memory_map

The region(s) holding an address, read as hex ($0400 or 0400), banked overlaps included

c64_lookup_opcode

A 6510 opcode by byte or mnemonic, legal and illegal

c64_pal_ntsc_diff

PAL and NTSC differences for a topic

Plan a program

Tool

Answers

c64_game_briefing

A game plan from a brief. It routes the brief to an archetype by its words (or takes one), proposes techniques, pitfalls, a toolchain split and a build order, and names the starter to begin from

c64_demo_briefing

The same for a demo, with an optional demo archetype (cracktro, demo intro, pack intro, dentro, 4K party intro)

c64_check_compatibility

Whether techniques can share a program. Hard conflicts include CPU every line, an interrupt needing cycles the CPU never gives up, a constant sprite set, KERNAL banked out, the serial bus busy, a region mismatch, the same hardware unit owned twice and zero page used twice. Softer notes include shared registers and KERNAL routines, a unit shared or read while another drives it, init order, and KERNAL zero page clobbered, and as info the zero page two recipes of the techniques both use. Raster bands that do not overlap clear the line-sharing rules. Names given as name:phase are checked phase by phase, and across phases for a raster IRQ, sprites or a banked-out KERNAL left running against another phase's disk I/O. It follows each technique's prerequisites, and says what the graph does not know

c64_timing_budget

Cycles per raster line for one technique on PAL or NTSC: badline, IRQ entry and sprite DMA losses

c64_plan_budget

A technique list, per phase (play, transition, init), against a frame, with calls or items per frame (char_bullets ×0-12): a cycle range from measured figures, what was left out and why, what has no figure yet, and a verdict. Given a game design, it sets that game's measured frame beside the prediction

Build it

Tool

Answers

c64_technique_lookup

A technique: the registers and KERNAL routines it uses, what it requires and what requires it, the recipes that implement it, the pitfalls it avoids

c64_techniques_for

Techniques filtered by category, chip, region, register, recipe, prerequisite or the hardware unit they claim

c64_recipe_lookup

One recipe: metadata, the page, the machines it was verified on, the hardware units its listing claims. Given a technique name, the recipes that realise it, or "No recipe yet"

c64_recipes_for

Recipes filtered by toolchain, region, technique, file format or verified machine

c64_toolchain_hint

An idiomatic snippet for a toolchain and intent; Oscar64 by default. An intent that names a technique gets its recipe's listing, in KickAssembler when that technique's only recipe is KickAssembler

Avoid mistakes

Tool

Answers

c64_pitfalls_for

Pitfalls a register, KERNAL routine or technique triggers, and those a technique avoids

c64_lint_source

Pitfall rules run over your C or assembly source

c64_failure_diagnose

Crash patterns that match a symptom, ranked by keyword overlap

c64_lint_source (CLI: c64-kb lint game.c) compiles the pitfall pages into text rules. It checks for:

  • a read or read-modify-write of a SID register;

  • $DC02 cleared and never restored;

  • an empty-name OPEN of channel 15 followed by a read;

  • a $D012 busy-wait in a file that never installs an interrupt;

  • a zero LFSR seed;

  • an interrupt handler reaching ADC or SBC before CLD;

  • an unmasked store to $D016;

  • JMP ($xxFF).

Each finding is definite, likely or heuristic. It lints one file at a time, so silence is not a pass. The rules are in src/tools/lint/, and the CLI exits 1 on a definite finding.

Maintain and run

Tool

Answers

c64_health

Service health and the live figures

c64_ingest_doc

Writes a page under docs/ and ingests it at once

c64_coverage, c64_suggest_links, c64_report_gap

Coverage per category, suggested missing edges, and a record of a query that found nothing

c64_run_game

Runs an Oscar64 build (it needs the .dbj debug file) in VICE through vice-mcp, drives it, and returns a state trace and the screen. It needs vice-mcp built (VICE_MCP_PATH) and x64sc; the repo's windowless VICE is used when present

c64_re_session

Replays a session file (docs/game-design/studies/sessions/) headless in x64sc and reports the clock the game reached play. A session names a game image by SHA-1 in the local, uncommitted data/games/manifest.json (a PRG, or a file on a D64), and sets registers at the game's own input reads to get past a title that waits for fire. It needs the windowless x64sc (npm run vice:headless)

c64_re_snapshot

Replays a session to play and dumps all 64 KB of RAM and the I/O area at a chosen moment; decodes the VIC-II bank, screen, charset, bitmap, sprite pointers and the CPU port

c64_re_load_map

Runs a .prg or a session from power-on under a store trace and groups every store by the code that made it: loader stubs, depack stages, stores to RAM under I/O, and the entry point

c64_re_coverage

Runs a .prg or a session and maps which RAM the CPU ran as code, read as data or only wrote, over a number of frames of play

c64_re_irq_chain

Runs a .prg or a session headless in x64sc and reports its interrupt chain: every vector write, every raster line armed, and every handler entry with its line, cycle and frame; a JMP (pointer) handler is split into its targets. A .prg must be inside the repo or the temp directory. It needs the windowless x64sc (npm run vice:headless)

c64_re_frame_profile

Runs a .prg or a session headless in x64sc. Region mode times every occurrence of a region between a start and stop marker, in CPU cycles: worst, typical (median), count, unpaired starts and samples over one frame. Frame mode needs no markers: it times each interrupt handler per frame and splits the rest of the frame into main-loop work and the idle wait, giving a **Measured frame:** line for a game that has no timer of its own. A .prg must be inside the repo or the temp directory. It needs the windowless x64sc (npm run vice:headless)

c64_claims_watch

Runs a .prg headless in x64sc under a store trace and checks every store against the hardware units the program declares: a recipe's claims: keys, its techniques' Claims lines, explicit claims and the KERNAL routines it calls. Lists each undeclared store with its unit, addresses and PCs. Same PRG and VICE rules as the two above

The CLI has a command for every tool except the c64_coverage row and c64_run_game. It also has services, ingest, serve and version.

Resources are whole reference documents at c64://memory-map, c64://kernal-jumptable, c64://opcodes, c64://illegal-opcodes, c64://pal-ntsc, c64://vic-ii, c64://sid, c64://cia, c64://6510-cpu, c64://registers and c64://ontology. There is also c64://register/{name} for one register. Prompts: c64_demo_brief and c64_game_brief.

The graph

The same pages feed a graph in FalkorDB. It answers:

  • Which registers and KERNAL routines a technique touches, and which recipes implement it.

  • What a technique needs underneath it, and what builds on it.

  • Which pitfalls it triggers and which it avoids.

  • Whether two techniques can share a frame: resource demands, hardware units claimed (sprites, SID voices, CIA timers, the raster compare, vectors, zero page) and raster bands.

  • Which zero-page bytes a KERNAL call may and must clobber. That comes from a walk of the ROM and from VICE traces.

  • What a technique costs per frame, measured on a named recipe, and whether a set fits.

  • What shape a game is (its archetype) and which starter plays it.

  • What a whole game measured, per phase.

  • Which recipes were verified on which machine models.

docs/ONTOLOGY.md lists every node and edge, and the page line that produces each.

docs/

Directory

What you find

hardware/

VIC-II, SID, CIA, the 6510 with legal and illegal opcodes, the KERNAL jump table, the memory map, a register table, PAL vs NTSC

techniques/

One section per technique across raster, sprite, scroll, bitmap, banking, SID, CPU tricks, loaders, 3D, transitions, text, input, game logic, maths and file I/O. Each technique carries the metadata the compatibility and budget tools read

pitfalls/

Gotchas by area, each with a severity, what triggers it and the fix. c64-failure-patterns.md maps symptoms to causes

recipes/

Complete programs in Oscar64, KickAssembler and cc65, each with its build command, expected output, a committed VICE screenshot and the reasoning

toolchains/

Oscar64, KickAssembler and cc65 references with their error messages, and build and release tools (cartconv, cc1541, petcat, png2prg, sidreloc, Spindle), memory layout and release disks

runtime/

VICE, including how to read an exit screenshot, plus vice-mcp and sim6502

formats/

PRG, D64, T64, CRT, SID and more, and the IEC bus and 1541

game-design/

Game archetypes, whole-game designs with measured frames, design patterns, game structure, enemy behaviour, production planning, and the licence table for reference game sources

demo-design/

Demo archetypes and composition

art/, music/

Asset pipelines and music production

workflow/

The agent harness the starters share

Scope

The stock Commodore 64, PAL and NTSC, and the common peripherals the pages cover: the 1541 drive, the 17xx REU, cartridges (including EasyFlash), the 1351 mouse, paddles and the light pen. Out of scope: the C128, Mega65, SuperCPU and Ultimate II+.

Toolchains

  • Oscar64 is the default; c64_toolchain_hint answers with it unless asked for another, or unless the technique asked about has only a KickAssembler recipe, when it answers with that recipe's listing.

  • KickAssembler is for work where C costs too many cycles: stable raster interrupts, border opening, FLI, multiplexers. KickAssembler 5.25 is the version verified here.

  • cc65 has light coverage, mostly text-mode utilities.

The Oscar64 recipes were verified with a locally patched build: upstream 709bd70 plus one unpublished fix. Released Oscar64 fails many of them (#25), so CI skips the Oscar64 recipes for now. Miscompiles found along the way are reported with repros in #30, and CLAUDE.md lists the ones that cost time. Whether Oscar64's GPL-3.0 reaches programs built with its runtime is an open question (#31).

Configuration

Service

Host port

Qdrant (REST, gRPC)

7333, 7334

FalkorDB

7379

Ollama

11434

The Qdrant and FalkorDB ports are shifted from their defaults (6333, 6334, 6379), so another instance of either can run alongside.

Variable

Sets

C64_KB_DATA_DIR

Where state lives (npm install)

C64_KB_STORAGE

Where the containers' volumes live

QDRANT_URL, QDRANT_COLLECTION

The vector store and collection (c64_docs)

FALKOR_HOST, FALKOR_PORT, FALKOR_GRAPH

The graph store and graph name (c64)

OLLAMA_URL, EMBED_MODEL, EMBED_CONCURRENCY

Embeddings (mxbai-embed-large; another model must also give 1024 dimensions)

DOCS_DIR, ANALYTICS_DB

The docs to ingest and the analytics database

KICKASS_JAR, OSCAR64, CL65

Toolchains for the listing gate (the starters read the first two)

X64SC_BIN, VICE_MCP_PATH

The VICE binary, and vice-mcp for c64_run_game

Architecture

The pages in docs/ are the source of truth. Ingest reads each page once and writes it two ways:

  • Qdrant stores its chunks with dense and BM25 vectors for search.

  • FalkorDB stores the things the page defines, and their relations, as a graph. docs/CONVENTIONS-*.md define the structure the extractor reads.

Ingest runs in two passes: nodes first, then edges. A reference to a node that does not exist is reported, never dropped silently. A SQLite database records the query tools' calls, so queries that find nothing surface as gaps. The MCP server and the CLI share one set of tool functions. See docs/ARCHITECTURE.md.

Development

Command

What it does

npm run build

Compile to dist/

npm run dev, npm run dev:serve

Run the CLI or the MCP server from source

npm run services, npm run services:stop

Start or stop Qdrant and FalkorDB

npm run ingest

Ingest changed pages

npm run ingest:clean

Wipe and re-ingest everything. Needed after any metadata change, because the graph never removes an edge a page stopped asserting

npm test

Unit and integration tests, against throwaway stores (c64_test, c64_docs_test); test:unit alone needs no services

npm run typecheck, npm run lint, npm run format:check, npm run knip

Type-check, ESLint with a complexity budget, Prettier, unused code

npm run check:listings

Build every listing with its toolchain

npm run verify:recipes

Run every recipe in VICE and compare with its screenshot; --update re-baselines after a deliberate change

npm run claims:recipes

Run every KickAssembler recipe under claims-watch and fail on any store it and its techniques do not declare

npm run verify:templates

Make a project from every starter and run its checks; --selftest adds the broken-build test and each starter's own proofs

npm run vice:headless

Build a windowless VICE into .tools/, which every emulator run then prefers

npm run new-project

Start a project from a starter

CI runs the type check, lint, formatting, unused-code check and unit tests. It also runs integration tests against service containers, the listing and recipe gates for KickAssembler and cc65, and an install-and-ingest test of the packed package. It skips the Oscar64 listings and recipes until #25, and does not run the starters or a full ingest. npx lefthook install adds git hooks that run the fast gates on what you stage. Releases publish to npm from a version tag; CLAUDE.md gives the steps.

Contributing

Add a page to docs/ in the structure its docs/CONVENTIONS-*.md file defines, then run npm run ingest (or ingest:clean after changing a metadata line). Ingest warns about every reference to a node the graph does not have: fix the page. A listing that does not build does not land. A recipe's picture must match its screenshot, and a deliberate change is re-baselined and explained on the page.

CLAUDE.md holds the rules, the instruments and the gates. It is written for Claude Code, and the repo's .claude/ hooks enforce the rules as you edit:

  • a doc edit builds its listings, and re-runs a recipe in VICE when x64sc is found;

  • a TypeScript edit is formatted, linted and type-checked;

  • git add -A and --no-verify are refused.

The repo's Claude Code skills cover verifying a listing, auditing a page, and adding a page the graph can read. CONTRIBUTING.md covers setup and code conventions. SECURITY.md says how to report a vulnerability; a wrong fact is an ordinary issue.

vice-mcp drives VICE over MCP; c64_run_game needs it. sim6502 unit-tests 6502 code without an emulator. Nothing else here needs either.

License

BSD-3-Clause: the code, the documents and the listings. Third-party sources are cited; which may be adapted and which are used for facts only is recorded in docs/game-design/reference-game-sources.md. The package documents GPL tools (Oscar64, VICE) but ships none of their code.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    A universal MCP server providing persistent, structured memory through a knowledge graph with graph storage, semantic vector search, and multi-hop traversal for AI agents and IDEs.
    24 PyPI
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to persistently store and semantically search shared knowledge via MCP tools.
    2
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables LLM agents to query a structured knowledge library for search, explanations, related concepts, learning paths, examples, and cross-domain references via MCP.
    Apache 2.0