Onboarding an existing project #
Ultimate Tool does not require you to adopt its diagnostics SDK or its template
layout. An existing C64 project becomes a toolkit project by adding one
c64dev.toml beside its own build. That single file then drives the same
versioned build, target, run, and evidence operations that every interface
shares.
The onboarding tiers, the manifest fields they require, and the verified
projects each tier has carried are described in PORTABILITY.md.
This page is the short path for a developer bringing in a project that already
builds a PRG.
Start from the screen-observation template #
examples/existing-project/c64dev.toml
is a copyable schema 11 manifest that builds the project with its own make and
checks one screen. Copy it next to your build and change three things:
build.command: the argument array that builds the PRG.build.artifact: the PRG the build produces.tests.expected_screen: a bounded string that must appear on screen.
schema_version = 11
[build]
command = ["make", "build"]
working_directory = "."
artifact = "build/game.prg"
toolchain = "the project's own pinned toolchain"
build.command is an argument array, not a shell string. working_directory
and artifact are project-relative, and the build runs from
working_directory, so a relative program name such as ./tools/asm resolves
there exactly as it would for the launch itself. A bare program name is searched
on PATH.
Screen observation needs no source changes: it launches the built PRG, waits for
the screen to stabilize, and compares the visible text. It does not read the
mailbox. [diagnostics] remains part of the required manifest shape, so keep
the conventional values unless your project already reserves that memory. A
screen test rejects expected_terminal, startup_command, and
heartbeat_timeout_ms, because that tier provides none of them.
Check the local prerequisites before you run anything #
Bringing up a manifest usually means discovering a missing tool or a wrong path. The read-only prerequisite diagnosis reports those without building or launching anything:
$ ultimate-tool doctor --manifest c64dev.toml --target fake
It is deliberately split from execution and reports a versioned row per local requirement:
manifest: the file loads and passes manifest validation. A missing or malformed file is reported as a row, not as silence.build_executable: thebuild.commandexecutable resolves throughPATHor as an explicit path, and carries an executable bit.build_working_directory:build.working_directoryexists and is a directory.vice_executable(only when--target vice): the configured VICE executable resolves to an existing file. Nothing about it is executed or version-probed.ultimate_target(only when--target ultimate): reported asnot_checked.
Build-command inputs are not_checked: the manifest does not enumerate an
arbitrary command's source/dependency inputs, so doctor does not guess them or
execute the command. The explicit build or first-run materializer validates
those inputs later. Missing future build outputs are not missing prerequisites.
Each row is ready, missing, or not_checked. The overall report is ready
when no checked local requirement is missing; not_checked remains an explicit
limitation, not a verification claim. The process exits 0
when it is; otherwise it exits non-zero.
The command purposefully does none of the following: it does not build, spawn a
process, inspect a container image, probe a version, contact a target, read a
credential, or write under .ultimate-tool. It never runs a command from the
manifest. Missing build outputs are expected — the build has not run yet — and
are not reported as missing prerequisites.
The Ultimate row is not_checked because Ultimate readiness depends on network
reachability and device identity, which a local read-only diagnosis cannot
establish; that is the separate probe workflow, and it needs no credentials
here. Finding an executable is not verifying its version, and a ready report
is not evidence that the project builds, that a target was contacted, or that a
program passed.
Grow the manifest only as the project needs it #
Add fields when a real capability needs them, not up front:
- Real symbol analysis and budgets. On schema 7, declare
build.symbol_sources(an LLVM lld.mapor an llvm-mos.elf) plus optionalbuild.source_remapsso resolved addresses can map back to project-relative source lines. On schema 8, add[[build.budgets]]to observe or enforce section sizes and symbol gaps. SeeBUILD_ANALYSIS.md. - Mailbox diagnostics. Adopting the Rust-MOS SDK opts into ordered events, one acknowledged startup command, heartbeat hang detection, crash classification, and bounded crash-state evidence. This tier costs memory and toolchain work; adopt it only where that cost has been measured. A screen test is never silently promoted to mailbox support.
- Hardware. Screen-memory evidence on a C64 Ultimate requires the identity-pinned probe and the separate authorized deployment/reset path. Do not infer hardware behavior from VICE or host tests.
The unchanged-binary portability proof carried roguelike-c64 (Rust-MOS) and
Polyself from nethack-6510 (llvm-mos C with overlays and a REU image) through
this tier without source changes, then replayed the same artifacts on a pinned
C64 Ultimate. Those outcomes are recorded in PORTABILITY.md;
their private trees are not required to use the template here.
Related #
PORTABILITY.md— the onboarding tiers and their verified projects.CONTRACTS.md— manifest schema 11 and its additive fields.BUILD_ANALYSIS.md— symbols, remaps, and budgets.