A native AmigaOS 4 shared library for the Anthropic Claude API.
Status: ALPHA. The library builds, loads cleanly, and passes its 35-test harness against a live
api.anthropic.comendpoint - but the API surface is not yet frozen, on-target time is still measured in days rather than months, and several features (tool- use round-trip, chunked-encoding decode, OAuth, AmiSSL fallback) are pending. Expect bugs and breaking changes between releases. Not yet recommended for production use.
claude.library is an Exec-style .library that lets any AmigaOS 4
program talk to Anthropic's Claude language models. It speaks HTTPS
directly to api.anthropic.com over bsdsocket.library and AmiSSL,
parses the JSON replies, and exposes the result through a familiar
OS4 tag-driven interface (IClaude->Ask(...), IClaude->StreamAsk(...),
etc.). It also publishes a public CLAUDE ARexx host port so any
ARexx-capable application (YAM, CubicIDE, AmIRC, DOpus5, Hollywood, ...)
can use Claude with a one-line ADDRESS CLAUDE 'ASK "..."'.
- AmigaOS 4 developers who want to add Claude-powered features (chat, summarisation, translation, code assistance, etc.) to a C/C++ or Hollywood application without writing HTTPS, JSON or retry logic by hand.
- ARexx scripters who want to call Claude from any AmigaOS app
that exposes an ARexx interface, with no programming required
beyond
ADDRESS CLAUDE. - Tool authors who want a single shared dependency that handles the API plumbing across multiple programs - the library is ~90 KB on disk and loads once, regardless of how many consumers open it.
Because everything lives in one shared library, applications stay
small: a few IClaude-> calls plus whatever UI they need. No
application re-implements TLS, transport, JSON, conversation
history, streaming or response parsing.
| Status | Alpha - API not frozen, expect changes |
| Version | 53.1-alpha (initial release) |
| Target | AmigaOS 4.1 Final Edition, PowerPC |
| Size | ~90 KB on disk, statically linked |
| Runtime deps | bsdsocket.library v4+, amisslmaster.library v5+, newlib.library v53 |
| License | zlib |
- Opens HTTPS connections to
api.anthropic.com(or any compatible endpoint) usingbsdsocket.library+ AmiSSL directly. No libcurl embed, no .so dependencies. - Builds Anthropic
/v1/messagesrequests, parses responses, manages multi-turn conversation history. - Streams replies via Server-Sent Events into a caller-supplied
struct Hook, with a dedicated workerProcessso your Intuition loop stays responsive. - Renders Markdown replies to AmigaGuide (with working hyperlinks
via
amigaguide.library), plain text, or console-coloured output. - Publishes a public ARexx host port named
CLAUDEthat any ARexx-capable application (YAM, CubicIDE, AmIRC, DOpus5, Hollywood, …) can hit withADDRESS CLAUDE 'ASK "..."'and read the reply from theRESULTvariable. - Persists conversations as portable JSON via
SaveConversation/LoadConversation. - Reads the API key from
ENV:CLAUDE_API_KEYif not configured explicitly.
The library is designed to fail gracefully: every public method
checks its inputs, every transport call validates that
bsdsocket.library and AmiSSL are usable before dereferencing
interfaces, and any failure surfaces a structured error code plus a
human-readable string through IClaude->LastError. The library never
crashes its caller.
Runtime (on the AmigaOS 4 machine):
- AmigaOS 4.1 Final Edition (or compatible).
bsdsocket.libraryv4 or newer. Provided by Roadshow on a stock AmigaOS 4.1 install.amisslmaster.libraryv5 or newer, plus a workingAmiSSL_v3xx.library.newlib.libraryv53 (ships with AmigaOS 4.1 FE).dos.library,utility.library,rexxsyslib.library,amigaguide.library(all stock).
Build host:
- Docker Desktop (any recent version).
- The cross-compiler image
walkero/amigagccondocker:os4-gcc11(the build script pulls it on first use). - The AmigaOS 4 SDK headers under
$CLAUDELIB_SDK_DIR(defaults to~/sdk).
No host-side AmigaOS toolchain installation required — everything runs inside the container.
git clone https://github.com/<you>/ClaudeLibrary
cd ClaudeLibrary
./build.shThis produces three artefacts in bin/:
claude.library— copy toLIBS:on your AmigaOS machine.claudesh— minimal CLI consumer (claudesh "your prompt").test_claude_library— 35-test TAP-style smoke test.
Then on the AmigaOS side:
SetEnv CLAUDE_API_KEY "sk-ant-api03-..."
test_claude_library --live
#include <proto/claude.h>
struct Library *ClaudeBase;
struct ClaudeIFace *IClaude;
int main(void) {
struct ClaudeConv *conv;
STRPTR reply;
ClaudeBase = IExec->OpenLibrary("claude.library", 53);
IClaude = (struct ClaudeIFace *)
IExec->GetInterface(ClaudeBase, "main", 1, NULL);
IClaude->Configure(
CLA_DefaultModel, (uint32)CLAUDE_MODEL_HAIKU_4_5,
CLA_ConnectTimeout, 15,
TAG_END);
conv = IClaude->NewConversation(
CLA_System, (uint32)"You are a concise assistant.",
TAG_END);
reply = IClaude->Ask(conv, (CONST_STRPTR)"What year did the Amiga 1000 ship?",
CLA_MaxTokens, 64,
TAG_END);
if (reply) {
IDOS->Printf("%s\n", reply);
IExec->FreeVec(reply);
} else {
IDOS->Printf("error: %s\n", IClaude->LastError(conv));
}
IClaude->FreeConversation(conv);
IExec->DropInterface((struct Interface *)IClaude);
IExec->CloseLibrary(ClaudeBase);
return 0;
}Any time claude.library is open in a process that called
Configure(CLA_StartArexxPort, TRUE, TAG_END), the public port
CLAUDE accepts the following verbs:
| Verb | Action |
|---|---|
VERSION |
RESULT set to "claude.library 53.1" |
MODEL <name> |
switch the default conversation's model |
SYSTEM <text> |
set the default conversation's system prompt |
RESET |
discard the default conversation, start fresh |
ASK <prompt> |
send <prompt>; RESULT set to the reply text |
LASTERROR |
RESULT set to the last error string (or empty) |
/* askclaude.rexx */
ADDRESS CLAUDE
SYSTEM "You are a terse Amiga developer."
ASK "What is the V53 entry for FillPenA in graphics.library?"
SAY RESULTstruct StreamCounters { int delta; char buf[2048]; size_t len; };
static uint32 my_stream_hook(struct Hook *h,
struct ClaudeConv *conv,
struct ClaudeStreamEvent *ev)
{
struct StreamCounters *c = (struct StreamCounters *)h->h_Data;
switch (ev->cse_Type) {
case CSEV_Delta:
if (c->len + ev->cse_Length < sizeof(c->buf)) {
memcpy(c->buf + c->len, ev->cse_Text, ev->cse_Length);
c->len += ev->cse_Length;
}
c->delta++;
break;
case CSEV_Stop:
IDOS->Printf("\n[done after %d deltas]\n", c->delta);
break;
case CSEV_Error:
IDOS->Printf("\n[error: %s]\n", IClaude->LastError(conv));
break;
}
return 0;
}
struct Hook stream_hook = { .h_Entry = (HOOKFUNC)my_stream_hook,
.h_Data = &counters };
IClaude->StreamAsk(conv, prompt,
CLA_StreamHook, (uint32)&stream_hook,
TAG_END);The hook is called from the worker process on each event. To receive
events on your own task, have the hook post a struct Message to a
port you own.
+----------------------+
| your OS4 app |
+----------+-----------+
| OpenLibrary("claude.library", 53)
v
+----------------------+
| claude.library | ROMTag-based AmigaOS shared library
| (IClaude interface) | - tag-driven API
+--+-----+-----+-------+
| | |
| | +--> amigaguide.library (markdown rendering)
| |
| +--------> dos.library + utility.library + newlib.library
| (interfaces opened in libInit and per worker task)
|
+--------------> bsdsocket.library + amisslmaster.library
(HTTPS to api.anthropic.com)
Two long-running worker Processes exist when their features are
used:
claude.rexx-port— owns the publicCLAUDEMsgPort, dispatches ARexx commands. Spawned byConfigure(CLA_StartArexxPort, TRUE).claude.stream— runs the HTTPS streaming transport soStreamAskreturns immediately. Spawned perStreamAskcall.
Both workers OpenLibrary("newlib.library") in their own task context
so their per-task _REENT is initialised before any libc call. They
also AllocSignal their own shutdown signal — cross-task signal
allocation is invalid per exec.library/AllocSignal.
./build.sh # build everything (library + examples + tests)
./build.sh lib # library only
./build.sh tests # the test harness only
./build.sh cleanThe script invokes ppc-amigaos-gcc inside Docker via docker-cc,
which mounts the project tree at /work and the SDK at /sdk.
Override paths with environment variables:
CLAUDELIB_IMAGE=walkero/amigagccondocker:os4-gcc11 \
CLAUDELIB_PROJECT_DIR=/path/to/repo \
CLAUDELIB_SDK_DIR=/path/to/sdk \
./build.shA standard make works too:
make # library + examples + tests
make lib
make examples
make tests
make cleanBuild flags worth knowing:
-mcrt=newlib— uses newlib as the C runtime.-nostartfiles— no CLI startup glue; the ROMTag is the entry point.- No
-shared— the library is a regular ELF EXEC binary with a Resident structure scanned byexec.libraryat OpenLibrary time. Building with-sharedproduces a DYN object withlibc.so/libgcc.sodependencies that may load the wrong runtime under multi-libc setups.
The bundled TAP-style harness exercises every IClaude method end-to-end:
# On the AmigaOS machine:
test_claude_library # 35 tests, dry-run + ARexx port
test_claude_library --skip-rexx # skip the host-port dispatch test
test_claude_library --live # also hit api.anthropic.com (needs key)
test_claude_library --hold 30 # keep the CLAUDE port alive for 30s
# so external rx scripts can use itFor QEMU-based testing the repo also includes host-side helpers under
tests/:
drive_test.py— drives the on-target test via SerialShell.mcpd_client.py— generic MCPd JSON-RPC client (useful if your AmigaOS QEMU runs theMCPddaemon).
claude.library reads ENV:CLAUDE_API_KEY (global env) on first
use unless an explicit key is supplied via:
IClaude->Configure(CLA_ApiKey, (uint32)"sk-ant-api03-...", TAG_END);To persist the key across reboots on the guest:
SetEnv CLAUDE_API_KEY "sk-ant-api03-..."
Copy ENV:CLAUDE_API_KEY ENVARC:
Treat the key as a secret. The library does not log it; the request
sends it only in the x-api-key HTTPS header.
OAuth-against-subscription is not currently supported because Anthropic routes third-party OAuth tokens to a separate empty billing pool. An issue tracking eventual re-enablement is anthropics/claude-code#37205.
All methods take a struct ClaudeIFace *Self (implicit when called
through IClaude->...). Tag identifiers live under
(TAG_USER | 0x00CD0000) to avoid clashing with other libraries.
| Method | Purpose |
|---|---|
Configure(... TAG_END) |
Set API key, endpoint, default model, timeouts, debug flags, start ARexx port. |
NewConversation(... TAG_END) → ClaudeConv * |
Begin a conversation. Tags: CLA_System, CLA_Model, CLA_UseCaching. |
FreeConversation(conv) |
Release conversation memory; aborts any active stream first. |
SaveConversation(conv, "T:foo.json") |
JSON serialise. |
LoadConversation("T:foo.json") → ClaudeConv * |
JSON deserialise. |
Ask(conv, prompt, ... TAG_END) → STRPTR |
Synchronous request. Caller frees the reply via IExec->FreeVec. Tags: CLA_MaxTokens, CLA_Temperature, CLA_Model, CLA_TimeoutSecs, CLA_Image. |
StreamAsk(conv, prompt, CLA_StreamHook, &h, ... TAG_END) → LONG |
Async streaming via SSE; events delivered through a struct Hook. |
AbortStream(conv) |
Cancel an in-flight stream. |
AddTool(conv, name, desc, schema_json, hook) |
Register a tool the model can call. |
RenderMarkdown(md, format, dest, ... TAG_END) → LONG |
format is CLAR_AmigaGuide, CLAR_PlainText or CLAR_Console; dest is a filename. |
LastError(conv) → CONST_STRPTR |
Human-readable error message for the last failed call. |
LastErrorCode(conv) → LONG |
CLERR_* value. |
Full reference: see include/libraries/claude.h (tags + struct
layouts) and include/interfaces/claude.h (struct ClaudeIFace).
ClaudeLibrary/
├── include/ public SDK headers
│ ├── libraries/claude.h tags, structs, error codes
│ ├── interfaces/claude.h struct ClaudeIFace definition
│ ├── proto/claude.h global IClaude / ClaudeBase decls
│ └── clib/claude_protos.h C convenience prototypes
├── src/ library implementation
│ ├── library.c ROMTag + manager interface
│ ├── iface_main.c IClaude vector destinations
│ ├── config.c IClaude->Configure
│ ├── conversation.c NewConversation / Save / Load
│ ├── ask.c IClaude->Ask (sync)
│ ├── stream.c IClaude->StreamAsk (worker process)
│ ├── transport.c bsdsocket + AmiSSL HTTPS POST
│ ├── markdown.c markdown -> AmigaGuide / plain / console
│ ├── rexx_port.c public CLAUDE ARexx host port
│ ├── tools.c tool-use registry
│ └── cjson_mini.c vendored compact JSON
├── examples/
│ └── claudesh/main.c minimal CLI consumer
├── tests/
│ └── test_claude_library/main.c 35-test TAP harness
├── docker-cc cross-compile wrapper
├── build.sh / Makefile build entry points
└── LICENSE zlib
Release stage: Alpha. The library is functional and well-tested on QEMU, but the public API may still shift between releases as real-world consumers shake out rough edges. Pin your build to a specific commit if you depend on it. The next planned milestone is Beta (API frozen at v53.x, tool-use round-trip wired, AmiSSL fallback, install script).
Working today (v53.1-alpha, initial release):
- Synchronous
Askagainstapi.anthropic.comover real TLS. - Streaming
StreamAskwith SSE delta parsing. - Conversation save/load.
- Markdown → AmigaGuide / plain / console.
CLAUDEARexx host port with end-to-end message dispatch verified by the TAP harness.- All 35 unit tests pass on QEMU AmigaOne (claude-backup-base_a1).
Planned:
- Tool-use multi-turn loop (
AddToolregisters, but thetool_use/tool_resultround-trip is not yet wired into the request cycle). - Chunked transfer-encoding decoding (currently the request uses HTTP/1.0 to sidestep chunked).
- OAuth Bearer auth (deferred — see Authentication above).
- AmiSSL fallback if AmiSSL is unavailable.
- A real install script (Installer-format).
Contributions welcome — please open an issue first for non-trivial changes. The project deliberately avoids non-ASCII characters in source and runtime output (the AmigaOS console is Latin-1 and serial-capture pipelines mishandle multi-byte UTF-8); please respect that in PRs.
Run the full test harness before submitting:
./build.sh tests
# then on the AmigaOS target:
test_claude_libraryzlib — see LICENSE. Deliberately liberal so any OS4
application can link against claude.library without licensing
friction.
- The Anthropic team for the Claude API and the public OS4 documentation efforts.
- The
walkero/amigagccondockerimage which makes cross-compiling for OS4 painless. - The
rolsen74/amy_skeletonsreference library skeleton, which shows the modern AutoInit pattern used here. - The clib4 project for documentation of how a real .library works on OS4 PPC.