# Clunkyard robot SDK

Start from the working project for your language in the workbench. Change
its tactics, save and build. The arena supplies the robot core and its
language binding; a project does not need to copy the SDK.

For your own editor, clone a [language starter](https://github.com/clunkyard/game-kit)
and follow [Develop a robot on your computer](../docs/player-kit.md). Use your
installed toolchain, download only its SDK, and run real matches with `make match`.
Use [private Git](../docs/private-git.md) to push changes back to a saved arena bot.
The small Makefile calls the shared npm CLI. Without Make, run
`npx @clunkyard/cli build`, `match` and `replay` from the project.

JavaScript and TypeScript can install the Node 20+ API from npm:

```sh
npm install clunkyard@npm:@clunkyard/sdk
```

The `clunkyard` alias keeps local and hosted imports the same. The package
includes TypeScript declarations and the WebAssembly core. Use the language
starter and shared `@clunkyard/cli` for the separate match engine and replay
tools. Install
[@clunkyard/git](https://www.npmjs.com/package/@clunkyard/git) to clone and push
your saved arena projects; [the setup guide](../docs/private-git.md) covers
platform-specific installation and sign-in.

The core owns protocol 2 parsing, observations, contact tracking, geometry,
shot solutions, finite checks and act serialization. Each binding exposes
those operations in its language's style. A call to a control changes only
the fields supplied; a later call replaces those fields and keeps the rest.

[API names](../docs/sdk/names.md) lists every operation across the languages.
The generated pages in [docs/sdk](../docs/sdk/) and the READMEs under
[bindings](bindings/) include complete small robots and each language's
build and launch instructions. The full starter tactics live in
[src/public/starters](../src/public/starters/).

## Choose a surface

| Language family | Surface supplied by the arena |
| --- | --- |
| C | Generated header and native core library |
| C++, Rust, Go, Hew, Swift, Zig, Haskell, OCaml, Fortran, D, Ada, Nim, Mercury, Pascal, FreeBASIC | Generated native binding; hosted builds link the installed core |
| Python, R, Ruby, Perl, Lua, PHP, Julia, Common Lisp | Installed runtime package and native core |
| Java, Kotlin, Scala, Clojure | Shared Java binding through the Foreign Function and Memory API |
| C#, F#, PowerShell | Shared .NET binding and launcher |
| Erlang, Elixir | Native module and generated BEAM API |
| Prolog, CHR | Native module and generated predicates |
| JavaScript, TypeScript | Generated Node API on the core's WebAssembly build |
| CLIPS, Forth, APL, MiniZinc | Language adapter on the Python core binding |
| BQN | Language adapter on the Node core binding |
| Vane, Cadence, Glyph | Built-in interpreter using the core |
| WAT, AssemblyScript, C, Rust, Zig compiled to WebAssembly | ABI 4 core imports |
| Shell | A small `jq` protocol helper in [shell](shell/) |

Protocol 2 is the only robot wire protocol. A raw protocol robot may read
and write its own JSON; [the protocol reference](../docs/protocol.md)
describes the messages. The binding is the normal starting point.

## Write a robot

A Python robot subclasses `Robot`, overrides `on_start` when it needs
match-wide setup and implements `on_turn`:

```python
import clunkyard as cy

class Scout(cy.Robot):
    def on_turn(self):
        self.drive.set(throttle=0.5, turn=0.3)
        target = self.sensors.nearest
        if target:
            power = self.gun.power_for_flight_time(target.range, 1)
            aim = self.gun.lead(target, power)
            heading = aim.heading if aim else target.bearing
            pitch = aim.pitch if aim else target.elevation
            self.scanner.set(heading=target.bearing, arc=20, pitch=target.elevation)
            self.gun.aim(heading, pitch)
            now = self.gun.aim_now
            if (abs(cy.angles.angle_diff(heading, now.heading)) < 3
                    and abs(pitch - now.pitch) < 3
                    and self.gun.can_fire(power, 10)):
                self.gun.fire(power)

cy.run(Scout())
```

The ready reply identifies the binding and core API version, for example
`clunkyard-python` and `2.0.0`. The wire protocol version and core API
version are separate contracts.

Observations describe the current turn. Optional results, such as a missing
precise contact or an unreachable shot, use the language's absent value.
Native C callers receive `CY_NONE`. Controls reject non-finite numbers.
Use the named subsystems for both reads and writes: `me`, `match`, `arena`,
`battery`, `gun`, `scanner`, `sensors`, `tracker`, `nav`, `clock`, `drive`,
`status`, `rng`, `angles` and `session`.

## Diagnostics and failures

Write diagnostics to standard error. Binding launchers preserve the protocol
output stream and redirect ordinary user diagnostics where the runtime
supports it. A raw protocol implementation must send exactly the reply due
for each input line and flush it.

A recoverable core fault answers the affected state with an empty act,
resets tracking at the next state and continues. After three core faults,
the handle answers later states with empty acts. A core fault is never
reported as the robot's crash. An unrecoverable output failure ends the run.
Language exceptions in user tactics follow the binding's documented rules;
uncatchable language or process failures can still end the robot.

A deliberate forfeit sends the core's forfeit reply. See the language's
README for its exception, predicate or function.

## Hosted builds

Builds have no network access. Use the standard library, the installed core
binding or source included in the project. The builder supplies include,
module and library paths. Compiled programs carry the robot's own output;
shared core packages stay in the runtime image. The runtime image contains
no compiler, assembler or linker.

A Go project with its own `go.mod` uses a builder-owned workspace to resolve
`clunkyard` locally. The builder does not rewrite the project's module.
C# and F# projects reference the installed binding with the `ClunkyardSdk`
MSBuild property; the .NET launcher loads that binding from the image.

Standard CPU limits depend on the runtime's frozen Season 3 tier and
measured overhead floor. Reflex uses DSL operations or WebAssembly fuel.
Open uses own time and supports a remote strategist. The selected match
shows its limits; [the manual](../public/community/manual.html#practice)
explains the classes.

## Develop off the platform

Install the native core and the binding under one SDK directory, then follow
the binding's README. `CLUNKYARD_LIB` may select the native shared library
for local checks. JavaScript and TypeScript use the core's WebAssembly build
through the supplied Node launcher. ABI 4 robots run through the Wasmtime
host; see [the WebAssembly SDK](wasm/README.md).

The JavaScript npm package runs on Windows, macOS and Linux with Node 20+.
Native SDKs also support selected languages on Apple Silicon, Intel macOS
and Windows x86-64, alongside Linux x86-64/glibc 2.39+. The
[player kit](../docs/player-kit.md#supported-platforms) lists the language and
platform combinations, official toolchain installers and normal build commands.

## Maintain the API

`protocol/v2/api.js` is the API model. `make api` regenerates the C ABI,
record layouts, bindings, conformance drivers, references and name tables.
Edit the model or a generator template, then regenerate; do not edit a
generated surface by hand.

`make api-check` rejects stale output and reserved names. `make sdk-test`
checks the available language bindings against the shared conformance
vectors and compares the READMEs' small robots act for act. Local checks
report absent toolchains; `make sdk-test-image` requires every toolchain.
`make starter-test-image` builds and plays the complete starter projects
through all rulesets. `make check` combines the release checks.

## Reference pages

- [ada](/sdk/ada)
- [adapters](/sdk/adapters)
- [apl](/sdk/apl)
- [basic](/sdk/basic)
- [bqn](/sdk/bqn)
- [c api](/sdk/c-api)
- [c](/sdk/c)
- [chr](/sdk/chr)
- [clips](/sdk/clips)
- [clojure](/sdk/clojure)
- [cobol](/sdk/cobol)
- [common lisp](/sdk/common-lisp)
- [cpp](/sdk/cpp)
- [csharp](/sdk/csharp)
- [d](/sdk/d)
- [dart](/sdk/dart)
- [elixir](/sdk/elixir)
- [erlang](/sdk/erlang)
- [forth](/sdk/forth)
- [fortran](/sdk/fortran)
- [fsharp](/sdk/fsharp)
- [go](/sdk/go)
- [haskell](/sdk/haskell)
- [hew](/sdk/hew)
- [java](/sdk/java)
- [javascript](/sdk/javascript)
- [julia](/sdk/julia)
- [kotlin](/sdk/kotlin)
- [lua](/sdk/lua)
- [mcp](/sdk/mcp)
- [mercury](/sdk/mercury)
- [minizinc](/sdk/minizinc)
- [names](/sdk/names)
- [nim](/sdk/nim)
- [ocaml](/sdk/ocaml)
- [pascal](/sdk/pascal)
- [perl](/sdk/perl)
- [php](/sdk/php)
- [powershell](/sdk/powershell)
- [prolog](/sdk/prolog)
- [python](/sdk/python)
- [r](/sdk/r)
- [ruby](/sdk/ruby)
- [rust](/sdk/rust)
- [scala](/sdk/scala)
- [shell](/sdk/shell)
- [swift](/sdk/swift)
- [wasm](/sdk/wasm)
- [zig](/sdk/zig)
- [player kit](/sdk/player-kit)
- [private git](/sdk/private-git)
- [local trials](/sdk/local-trials)
- [arena languages](/sdk/arena-languages)
- [dsl workshop](/sdk/dsl-workshop)
- [vane](/sdk/vane)
- [cadence](/sdk/cadence)
- [glyph](/sdk/glyph)
