Contribution guide: CONTRIBUTING.md Support: SUPPORT.md
CoAkka is for application-owned work that needs a runtime boundary, not another fake backend API.
It gives application hosts a shared runtime vocabulary: target, route snapshot, typed payload, reply, deadletter, and delivery diagnostics.
Many teams create deployment-owned HTTP endpoints just to move work between application components or services. That spreads one application-owned contract across URLs, clients, retries, timeouts, status mapping, and error handling.
This repository shows that model through runnable samples for CoAkka Runtime connectors, the CoAkka Runtime CLI client, framework adapters, native integrations, and coakka-logger packages built from the public CoAkka artifact surface. Runtime samples currently include JVM, Python, Node.js, Bun, Electron, Tauri, Go, C#, Rust, Mojo, Zig, and native C/C++ lanes.
This repository is the runnable sample repository. Public binaries, packages, checksums, manifests, and release notes live in the artifact distribution repository:
Use coakka-samples when you want to run examples. Use coakka-publish when
you want to download a released archive or package directly. The fastest direct
download entrypoint is the GitHub Release page:
The sample runner will resolve artifacts from a sibling coakka-publish
checkout when present, or from the public raw GitHub artifact URLs when that
checkout is absent.
| Question | Short answer |
|---|---|
| Problem | Internal application work often becomes fake backend HTTP, spreading one contract across URLs, clients, retries, timeout mapping, status mapping, and logs. |
| What CoAkka is | A runtime boundary for application capabilities: callers ask a typed target, route snapshots decide ownership, and replies/deadletters carry runtime diagnostics. |
| What it is not | Not a replacement for public HTTP/gRPC edges, auth, service discovery, deployment policy, CQRS, or ordinary direct calls that are already enough. |
| Where to download | Public artifacts live in coakka-publish; this repo consumes those artifacts through runnable samples. |
| Benchmark posture | Benchmarks are evidence and regression guardrails, not the main product claim; the harder shift is modeling app-owned work as runtime targets instead of another L7 API. |
| Run this | bash run.sh runtime-client for the published runtime-client CLI, then bash run.sh containers node-python or bash run.sh runtime jvm basic for app-host connector samples. |
| Observe this | The CLI reports runtime build diagnostics from the published client archive. App-host samples then show targets, process ownership, and runtime outcomes instead of hidden REST fallback behavior. |
Fast public path:
git clone https://github.com/phuong-tran/coakka-samples.git
cd coakka-samples
bash run.sh runtime-client
bash run.sh containers node-pythonThe first sample verifies the published coakka-client archive from
coakka-publish. The second sample pulls the published Docker Hub
Node.js/Python images and runs a two-process runtime path. Use
CoAkka Public Artifacts 1.3.1
for direct archive, package, checksum, manifest, or release-note downloads.
Evidence and repo boundaries: Production Evidence, Repository Boundaries, CoAkka Ecosystem Naming, Production Readiness.
- Where Downloads Live
- Start Here
- What Problem Does CoAkka Solve?
- CoAkka Naming
- See It In 3 Minutes
- Before And After
- Which Sample Should I Run?
- When CoAkka Helps
- Incremental Rollout
- Core Runtime Vocabulary
- How To Read This Repository
- Why CoAkka Exists
- Runtime First
- Architectural Value
- Boundary Patterns
- Questions And Answers
- How It Works
- Cluster Routing
- Sample Integration Checklist
- Runtime Scenarios
- Framework Adapters
- CoAkka Runtime Client
- CoAkka Runtime Inspect
- Logger
- Runtime And Logger Together
- Quick Start
- Requirements
- Runtime Configuration Notes
- Integration Guide
- Readiness
- Future Connector Scope
- Samples
- Runtime Capability Samples
- Container Sample Direction
- Benchmark And Load Status
- Artifact Source
- Public Status
- Direct Runs
- CI
- Diagnostics
- License And Trademark
CoAkka is for application-owned work that needs a real boundary but should not have to become another backend network API.
The common failure mode is familiar:
controller -> backend URL -> HTTP client -> backend endpoint
That endpoint is not a public product API. It exists because one process, app module, worker, or language runtime needs to ask another one to do work. Over time, the contract spreads across path strings, client wrappers, status-code mapping, retry behavior, timeouts, and logs.
CoAkka keeps the boundary in runtime terms:
controller -> runtime target -> owning handler
The caller asks for a typed target. The runtime route snapshot decides where
that target is owned. If delivery fails, the result is a runtime failure or
deadletter with source, target, route generation, and reason.
CoAkka does not replace HTTP at real edges, gRPC at real service API boundaries, CQRS, authorization, ingress, service discovery, or deployment policy. It gives application hosts a shared runtime vocabulary for application capabilities that should not need fake REST just to gain a boundary.
CoAkka is the ecosystem and brand prefix. Public sample docs should name the
specific product surface when the distinction matters:
| Name | Meaning |
|---|---|
CoAkka Runtime |
Runtime product family: targets, route snapshots, replies, deadletters, lifecycle, and diagnostics. |
coakka-runtime-core |
Native runtime engine and public C ABI surface. |
coakka-runtime-connector |
Host-language and framework connector packages consumed by app-hosts. |
coakka-runtime-client |
CLI runtime client. The published command and archive names use coakka-client. |
coakka-runtime-inspect |
Browser runtime explorer and route-try UI. |
coakka-logger |
Bounded logger product surface, separate from runtime routing. |
When using the CLI archive, run coakka-client. coakka-runtime-client is the
product lane and sample directory name, not an executable name in this release.
The existing runtime/ and logger/ directories are stable sample command
categories. Do not read those path names as the full product taxonomy. For the
wording rule, read CoAkka Ecosystem Naming.
The fastest terminal-first check is the runtime client path:
bash run.sh runtime-clientWatch the runtime-client CLI walkthrough:
Full recording: coakka-runtime-client.mp4
Read the runtime-client docs for the product introduction, command usage, and technical notes: runtime-client/docs/ (public GitHub path). Direct platform downloads are in runtime-client/README.md#published-release.
That verifies the published coakka-runtime-client lane by resolving the
coakka-client 1.3.1+2215b0f archive, checking its SHA256 against the
public manifest, then running version and doctor from the unpacked native
prefix.
For a live request/reply path through the published CLI and native service, run:
bash run.sh runtime-client docker-bundleAbbreviated expected shape; Docker Compose status lines and generated message IDs may vary:
created:customer#42
created:customer#ask
created:customer#script
created:customer#script-ask
{
"ok": true,
"message_kind": "MESSAGE_KIND_RESPONSE",
"payload_text": "created:{\"customer_id\":\"script\",\"tier\":\"violet\"}"
}
That Docker path is for Linux bundle verification from the published artifact
layout. The older docker-demo runner command remains available as a
compatibility alias for the existing release archive path.
For a more visible Docker CLI walkthrough, run:
bash run.sh runtime-client docker-walkthroughThat command uses the same published Docker bundle, starts two native runtime
service containers, prints their service names, ports, and routes, then runs
coakka-client from the CLI container against both services. It also runs one
shell script that switches from one runtime endpoint to the other inside the
same CLI session.
For the Docker Hub path with no local artifact unpacking or Compose build, run:
docker run --rm docker.io/gabrielgun1983/coakka-runtime-client-demo:1.3.1-2215b0f-remoteor through the sample runner:
bash run.sh runtime-client dockerhub-demoThat image starts two native runtime services inside the container and uses the
packaged coakka-client to call both routes.
The fastest browser-visible app-host path is the Node.js/Python container path.
It uses the refreshed 1.3.1 runtime artifact line, so you can test a
cross-process runtime delivery path without installing Node.js, Python, Go,
Java, or native build tools.
Docker Hub is not the canonical artifact download surface. It is the prebuilt
sample-image lane. Public native archives, connector packages, CLI client
archives, checksums, and manifests still live in coakka-publish.
Docker Hub image tags for this release train:
docker.io/gabrielgun1983/coakka-runtime-client-demo:1.3.1-2215b0f-remote
docker.io/gabrielgun1983/coakka-runtime-inspect-sample:1.3.1-4ce41f19-remote
docker.io/gabrielgun1983/sample-node-web:1.3.1-bda2ef5-0a0aa76-remote
docker.io/gabrielgun1983/sample-python-store:1.3.1-bda2ef5-0a0aa76-remote
Those tags are the published runtime-client, runtime-inspect, and Node.js/Python
container image lines used by these samples. The runtime-client demo image
bundles the published coakka-client 1.3.1+2215b0f and native demo service
artifacts. The runtime-inspect sample image copies the published Linux
coakka-runtime-inspect Linux 1.3.1+4ce41f19 archives without installing
native implementation runtime packages. The Node.js/Python sample images
install the pinned Node.js and Python connector artifact set
1.3.1+bda2ef5-0a0aa76 over the native runtime base line 1.3.1+bda2ef5.
Repo-local rebuilds use the same connector set over
coakka/runtime-base:1.3.1-bda2ef5-local.
Run the visible container sample:
bash run.sh containers node-pythonThen open:
Node.js web -> Python store:
http://localhost:8080
http://localhost:8081
Stop every container sample:
bash run.sh containers downThese samples show two real processes, two language hosts, browser-visible state changes, and runtime delivery with no REST fallback between the sample services.
Current visual evidence from the Node.js web to Python store container sample:
What to observe:
- the browser-visible web app sends application work to another process
- the runtime path uses CoAkka runtime delivery, not REST fallback
- the target owner can be in another language runtime
- delivery stays explicit across language and process boundaries
The sample path is:
browser
-> web app or app-host
-> connector
-> CoAkka runtime
-> target handler in the owning process
-> runtime reply
-> web UI
Before:
Spring API -> backend HTTP -> Go store
Node job -> backend HTTP -> Python worker
C# API -> backend HTTP -> JVM renderer
After:
Spring API -> CoAkka target -> Go store
Node job -> CoAkka target -> Python worker
C# API -> CoAkka target -> JVM renderer
The point is not that every backend HTTP call is wrong. The point is that application-to-application work often wants a stable capability name, typed payload, route ownership, and explicit delivery outcome more than it wants another URL surface.
| Goal | Start with | Why |
|---|---|---|
| See CoAkka work without installing language toolchains | bash run.sh containers node-python |
Runs two real processes with browser-visible state and no backend HTTP fallback. |
| Understand the smallest runtime API | bash run.sh runtime jvm basic |
Shows CoAkka.local, a local handler, and one ask/reply without route boilerplate. |
| Understand explicit runtime wiring | bash run.sh runtime jvm java-basic or the basic sample for another language |
Shows start spec, process-owned route, handler registration, ask/reply, and stats. |
| Understand route misses and delivery failures | bash run.sh runtime jvm deadletter or bash run.sh runtime python deadletter |
Shows a missing target becoming a matched deadletter instead of a vague timeout. |
| Understand route generation and reload | bash run.sh runtime python hot-reload |
Shows newer route snapshots being applied and stale/invalid snapshots rejected. |
| Understand browser runtime exploration | bash run.sh runtime-inspect check then bash run.sh runtime-inspect published-smoke or bash run.sh runtime-inspect docker-smoke |
Shows inspect as the UI sibling of coakka-client using the public native UI archive or a local Docker image built from it. |
| Understand a normal application workflow | bash run.sh scenario customer-crud spring-boot-starter-local dev |
Shows browser/API edge plus runtime capabilities in one same-process app. |
| Compare same-process app shape with cross-process shape | bash run.sh scenario customer-crud spring-boot-spring-boot dev |
Keeps customer traffic runtime-only between web and store processes. |
| Start from Spring Boot annotations | runtime/scenarios/customer-crud/spring-boot-starter-local |
Uses @CoAkkaHandler and CoAkkaRuntimeClient instead of manual route/handler wiring. |
| Start from explicit connector wiring | runtime/scenarios/customer-crud/spring-boot-single-process |
Keeps route declaration and handler registration visible in application code. |
More local starts:
bash run.sh quickstart
bash run.sh doctor
bash run.sh listFor dependency snippets and the minimal host skeleton, read runtime/README.md#copy-paste-starter-shapes. For a longer rollout path, read docs/integration-path.md.
CoAkka is useful when:
- application work crosses process or language boundaries
- application-owned contracts are spreading across ad-hoc REST or gRPC clients
- teams want explicit delivery diagnostics for route miss, timeout, queue pressure, and unavailable endpoints
- a system is migrating gradually across runtimes
- the same capability may start same-process and move cross-process later
CoAkka is probably not necessary when:
- direct in-process calls are already enough
- the boundary is a real public HTTP or gRPC API
- the added runtime vocabulary does not solve a coordination or diagnostics problem
- the team does not need route ownership, request/reply matching, deadletters, or runtime delivery stats at that boundary
Logger samples are included because the public artifact surface ships logger packages too, but the main README story is runtime capability delivery.
CoAkka is not a rewrite-first platform. It does not ask teams to break working legacy systems, replace public APIs, standardize every service on one framework, or migrate the whole architecture at once.
The practical rollout path is smaller:
pick one runtime boundary
-> add a host-language connector
-> route one typed target through CoAkka
-> inspect delivery, reply, stats, or deadletter evidence
-> expand only if the boundary becomes clearer
This matters because many architectural ideas are rejected for operational reasons rather than conceptual ones. A model may be sound, but if the first step requires a rewrite, a platform reset, or a large migration event, most teams will not adopt it.
CoAkka is more useful when setup stays simple, configuration stays lightweight, and legacy systems can remain in place. In that shape, it becomes a practical boundary improvement rather than a disruptive architecture bet: reduce fake backend HTTP, standardize runtime capability delivery, and improve diagnostics one boundary at a time.
Target: the stable capability address the caller asks for, not a URL, class, or function name.Envelope: the runtime message wrapper carrying target, source, payload identity, payload bytes, request context, timeout, and matching metadata.Payload identity: the message type, schema version, and payload format used to version request, reply, and event bodies.Headers/ metadata / extra params: small request context such as tenant, request id, trace id, or idempotency key; business arguments belong in the payload.Route generation: the version of the route snapshot used to decide where a target can be delivered.Deadletter: a structured terminal delivery result for route miss, queue pressure, unavailable endpoint, or another explicit delivery failure.Timeout: the caller's wait budget for an ask, enforced by runtime/connector pending-request matching; it is not a business retry policy by itself.Retry: caller/application policy unless a sample explicitly says otherwise; retry only with idempotency and a bounded budget.
For the detailed connector, routing, envelope, deadletter, timeout, retry, and tuning model, read Runtime Message And Routing Model. For the cluster-style endpoint selection and failover model, read Runtime Cluster Routing.
Use this order for a first pass:
- Run one container sample first. It shows the visible path without requiring a local language toolchain.
- Open one basic sample in a language you know and look for five things: start spec, route target, process-owned handler registration, typed ask or event, and stats or deadletter output.
- Read a customer CRUD scenario. Those samples show why the runtime boundary is useful in a normal application workflow.
- Then read the model sections below when you want the full vocabulary and architectural rationale.
Shortest non-container paths:
bash run.sh runtime jvm basic
bash run.sh runtime native basic
bash run.sh runtime native pressureCoAkka is aimed at systems where process, language, and deployment boundaries are part of the design problem.
Modern systems are rarely rewritten in one clean step. A JVM service may be stable, a Python worker may own a data path, a Node.js service may sit at the edge, a Go utility may handle operational work, and a desktop application may still be part of the real workflow.
CoAkka exists to give those pieces a shared runtime contract that can be adopted gradually. The goal is not to replace a working legacy system before value can be measured. The goal is to put a typed, inspectable boundary around one workflow, one process, or one integration point at a time.
That coexistence is part of the design advantage. Existing public edges can stay public, direct in-process calls can stay direct, and legacy services can keep running while one noisy runtime boundary is made explicit. If the first step is small and reversible, a team can evaluate the runtime model from real delivery evidence instead of committing to a migration plan up front.
The intended rollout path is incremental:
- keep the existing service or desktop application
- add a small host-language connector at the boundary
- route typed requests, replies, events, and diagnostics through the shared native runtime contract
- migrate one process, one integration point, or one workflow at a time
CoAkka does not require a team to migrate a whole system before learning whether the runtime boundary helps. A team can wrap one noisy runtime integration, one polyglot handoff, one workflow, or one failure-prone route first. The existing HTTP APIs, framework controllers, services, jobs, and deployment shape can keep running around that experiment.
This matters for real systems because the first useful result is often not a rewrite. It is a clearer answer to one operational question:
Who sent the work, which target owned it, which route snapshot was active, and
why did delivery succeed, time out, or become a deadletter?
If that answer is valuable for one boundary, the team can expand from there. If direct calls are already enough for a small path, that path can stay direct.
That boundary can be embedded inside an application, placed beside a service as a sidecar, or used as the point where adapters talk to existing integration systems. Camel, MQTT, message brokers, files, serial devices, HTTP services, and other legacy entrypoints are natural places to attach adapters. The samples in this repository do not claim every adapter is already shipped; they show the runtime contract those adapters can share.
The samples are meant to be easy to run on a local development machine, but Linux validation is part of the runtime story. Native loading, service supervision, memory pressure, and deployment packaging are part of the system, not an afterthought.
Runtime v2 is the main CoAkka surface in this repository.
It is not presented here as a generic framework. These samples focus on a smaller boundary problem: once services cross process and language boundaries, each connector can end up reinventing framing, routing, request/reply, one-way event delivery, lifecycle, deadletter behavior, and diagnostics.
Runtime v2 provides one native runtime contract for those concerns. Host languages keep local ergonomics, while the native runtime owns the shared routing table, request correlation, deadletter accounting, lifecycle snapshots, and version diagnostics.
Messages are typed. A runtime payload declares:
- message type
- payload schema version
- payload format
The samples use JSON where readability matters. The runtime contract also has payload format space for Protobuf, Thrift, MessagePack, plain text, and binary payloads when a workflow needs a different wire shape.
When run with a matching public artifact set, basic same-process samples and cross-process customer scenarios keep business traffic on the runtime path; if runtime delivery fails, the UI/API returns an explicit runtime error instead of hiding the failure behind a REST fallback.
The value is not adding one more transport option. The value is standardizing the boundary between an application host and the runtime so the same delivery terms apply across services and languages:
- one runtime contract for JVM, Python, Node.js, Bun, Electron, Tauri, Go, C#, Rust, Mojo and Zig source packages, and native C/C++
- one vocabulary for target names, route snapshots, generations, and handler ownership
- one diagnostic model for request/reply, deadletters, queue pressure, and lifecycle
- application hosts keep feeding config from their own environment
- the C/C++ runtime core keeps behavior consistent instead of each framework inventing a different routing, correlation, or failure model
That helps when a system has started to accumulate informal application-owned contracts:
- a small service change requires edits in several other services
- each team implements routing, retry, correlation, and error handling differently
- moving one implementation to another language forces client and config churn
- failures show up as vague timeouts instead of route and delivery evidence
- the real contract is scattered across code, config, logs, and team memory
The hard part is usually not the transport mechanics. It is the mindset shift: keep real HTTP/gRPC at API edges, and stop promoting app-owned handoffs into extra L7 services when a runtime target is the cleaner boundary.
For that value to stay reliable in production, every release and deployment profile has to keep three properties explicit:
- the remote transporter runs reliably under load, reconnect, process restart, and controlled route reload
- connector ergonomics stay simple when an application feeds config, registers handlers, and sends asks/events
- diagnostics are sharp enough for operators to identify the route, generation, target, pending work, and deadletter reason quickly
The intended shape is a small runtime core, host-language connectors that feed startup config and business handlers, route snapshots that can be re-applied with defined semantics when needed, and infrastructure that still owns ingress, discovery, and deployment policy. That gives an organization a shared integration substrate without forcing every service into the same application framework.
These are the practical patterns the samples are trying to make concrete.
Name application-owned work by target, not URL. In REST, teams often encode an application-owned call shape across method, path, query string, and headers:
POST /backend/customers/cust-001/hold?tenant=acme
x-request-id: req-123
With CoAkka, responsibility is split more directly:
target = customer.hold
payload = {"customerId":"cust-001","reason":"manual_review"}
headers = {"tenant":"acme","x-request-id":"req-123"}
Do not use envelope headers as a second payload schema. If a value is part of the business command or query, put it in the payload and version it through payload identity. Use headers for small request context that should stay next to the envelope.
Move implementations without renaming the capability.
target = customer.store
generation 12 -> Go store
generation 13 -> JVM store, Node.js store, or replicated store endpoints
The target and payload contract can stay stable while endpoint placement changes through route config.
Start same-process and move later when needed.
controller -> CoAkka target -> same-process handler
controller -> CoAkka target -> peer-runtime handler
The first version can stay compact. If the handler moves later, the app keeps the same target, source, route-generation, and deadletter vocabulary.
Make delivery failure answerable. CoAkka diagnostics should help identify:
- who sent the work
- which target was requested
- which route generation was active
- whether delivery missed a route, hit queue pressure, timed out, or matched a response/deadletter
For deeper comparisons with REST/gRPC, service mesh, CQRS, Event Sourcing, workflow engines, brokers, security policy, observability, and business versus runtime boundaries, read docs/qna.md.
Common positioning questions are collected in docs/qna.md. Start there for the quick decision table and comparisons with gRPC, Dapr, Akka/Erlang/Elixir, CQRS, Event Sourcing, Temporal-style workflow engines, Kafka/RabbitMQ, Saga, Istio, mTLS, auth/authz, observability, and logger scope.
CoAkka keeps a hard boundary between the application host and the native runtime core.
flowchart LR
ingress["Ingress"]
connector["Connector"]
runtime["CoAkka runtime"]
handler["Process-owned handler"]
peer["Peer runtime"]
diagnostics["Diagnostics"]
ingress --> connector
connector --> runtime
runtime --> handler
runtime --> peer
runtime --> diagnostics
The connector layer adapts the host language and framework. It reads host config, builds route snapshots, registers process-owned handlers, encodes payloads, and maps framework lifecycle into runtime start and shutdown calls.
The native runtime core owns the shared behavior: active route generation, target-to-endpoint resolution, bounded queues, request/reply correlation, deadletters, health, stats, and the local or remote transporter boundary.
CoAkka runtime does not fetch platform configuration by itself. The connector or framework adapter owns that work: it reads the host environment, validates the shape, builds a start spec and route snapshot, then passes those values through the runtime API.
flowchart LR
sources["Config sources"]
adapter["Connector validates and maps"]
snapshot["Start spec + route snapshot"]
runtime["Runtime API"]
active["Active runtime state"]
sources --> adapter
adapter --> snapshot
snapshot --> runtime
runtime --> active
For most container deployments this is startup work, not a continuous hostname update loop. A pod or service gets its advertised host from Kubernetes metadata, Service DNS, environment, or a control plane when the process starts. Replicas of the same app role normally share the same runtime port.
In Kubernetes this should feel like ordinary application configuration: read
env, framework config, Helm values, ConfigMaps, Service DNS, or pod metadata at
startup, then let the connector map those values into RuntimeStartSpec and
the initial route snapshot.
Configuration sources can be files, process environment, framework config, Kubernetes ConfigMaps or Secrets, Consul, another config service, or an operator/control plane. Those sources stay outside the runtime contract.
The runtime is deliberately platform-agnostic:
- it does not read config files, environment variables, Spring Config, Consul, Kubernetes objects, or service mesh state
- it does not discover services by itself
- it does not decide business retry policy
- it does not know Spring, Kubernetes, Node.js, Go, or Python framework semantics
- it only receives explicit API calls from the host connector
That keeps responsibilities testable. Runtime tests can focus on route application, target resolution, correlation, queue pressure, deadletters, and lifecycle. Connector tests can focus on config mapping, payload encoding, handler registration, and framework shutdown behavior.
Route apply is the critical API shape. Startup uses it for the initial route snapshot. Hot reload uses the same shape later if an operator or control plane needs to change routes without restarting the process:
applyRoutes(generation, routes) -> applied | stale_generation | invalid_snapshot
flowchart TD
snapshot["route snapshot"]
validate["validate"]
compare["newer generation?"]
applied["applied"]
stale["stale_generation"]
invalid["invalid_snapshot"]
snapshot --> validate
validate --> invalid
validate --> compare
compare --> applied
compare --> stale
The result is intentionally small:
applied: runtime atomically swaps to the new route tablestale_generation: runtime keeps the current route table because the snapshot is not newerinvalid_snapshot: runtime keeps the current route table because the snapshot shape is not acceptable
The request path then uses the active route snapshot. Same-process delivery is the compact case:
sequenceDiagram
participant App as App code
participant Connector as Connector
participant Runtime as Runtime
participant Routes as Active routes
participant Handler as Process-owned handler
participant Deadletter as Deadletter
App->>Connector: ask target B
Connector->>Runtime: submit envelope
Runtime->>Routes: resolve target
alt LOCAL endpoint
Routes->>Handler: deliver request
Handler-->>Runtime: reply
Runtime-->>Connector: match response
Connector-->>App: return result
else missing target
Routes-->>Deadletter: record miss
Deadletter-->>Runtime: terminal outcome
Runtime-->>Connector: match deadletter
Connector-->>App: return failure
end
Multi-process delivery uses the same target vocabulary, but the active route points to a peer runtime:
sequenceDiagram
participant AppA as Service A app
participant ConnectorA as Connector A
participant RuntimeA as Runtime A
participant Routes as Active routes
participant RuntimeB as Runtime B
participant ConnectorB as Connector B
participant HandlerB as Service B handler
participant Deadletter as Deadletter
AppA->>ConnectorA: ask target B
ConnectorA->>RuntimeA: submit envelope
RuntimeA->>Routes: resolve target
alt peer endpoint
Routes->>RuntimeB: deliver request
RuntimeB->>ConnectorB: dispatch
ConnectorB->>HandlerB: invoke handler
HandlerB-->>ConnectorB: reply
ConnectorB-->>RuntimeB: response envelope
RuntimeB-->>RuntimeA: response
RuntimeA-->>ConnectorA: match response
ConnectorA-->>AppA: return result
else missing target
Routes-->>Deadletter: record miss
Deadletter-->>RuntimeA: terminal outcome
RuntimeA-->>ConnectorA: match deadletter
ConnectorA-->>AppA: return failure
end
The caller does not call a backend HTTP controller in either path. It asks a
runtime target; the active route snapshot decides whether that target maps to
a handler owned by this process, a peer runtime, or a deadletter.
The semantics need to stay strict:
generationmust increase for a new snapshot- apply is atomic; a failed apply leaves the active route table untouched
- diagnostics always report the active generation
- route misses produce deadletters with target, reason, and generation context
- in-flight requests continue to be matched by correlation; new sends observe the active route snapshot at send time
- rollback is another explicit snapshot with a newer generation, not a partial mutation of runtime state
Cluster-style delivery is still the same call-site shape. The app asks for a target; the route snapshot may contain several eligible peer endpoints; the runtime selects and, when safe, fails over within the same request lifecycle. The app still owns business retry policy after a terminal timeout or deadletter.
Read Runtime Cluster Routing for the Mermaid diagrams, route snapshot examples, call-site sample, and the transport compatibility rule.
The samples are written as an integration path, not only as API snippets. A useful runtime sample should make these boundaries visible:
- Start the runtime participant.
- Feed route config from the app host into the runtime.
- Register the process-owned handler for the target this process owns.
- Send a typed ask or event to a peer target.
- Handle route miss and delivery deadletters explicitly.
- Observe active generation, pending requests, matched responses, and deadletter counters.
- Shut the runtime down through the host framework lifecycle.
The customer scenarios expose the important config knobs in application config:
local-targetlocal-hostlocal-portpeer-targetpeer-hostpeer-portgeneration
The shared customer-contract module holds the cross-service contract:
- message type constants
- payload schema version and format
- request and response DTOs
- delivery mode values used by API/UI diagnostics
/api/customers/runtime shows the route config that the connector fed into
the runtime, including configuredGeneration, localEndpoint, and
peerEndpoint.
The API responses distinguish how a request was handled:
runtimefor runtime delivery
There is no store REST fallback on the customer web path. If cross-process
runtime delivery fails, the web API returns RUNTIME_DELIVERY_FAILED so the
runtime failure is visible instead of hidden by a second transport.
Store and audit services run headless; even the Spring Boot store is configured
as a non-web application, so 8081 is the only browser/API HTTP surface.
The route hot reload capability is covered by runtime/python/hot-reload and
by the Spring Boot single-process customer scenario. Treat it as an operational
tool, not the normal happy path. Most container deployments can start with a
route snapshot derived from platform config and change routes by rolling out a
new pod set. The samples keep routes.yml, reload-routes, and generation
diagnostics visible so the apply semantics are concrete when live route changes
are needed.
The customer CRUD scenarios make the runtime boundary visible through an ordinary workflow: add, edit, delete, and list customer data.
The workflow is web-based because a browser is easy to inspect, but the runtime is not web-specific. The same request/reply, one-way event, deadletter, and diagnostic contract can be used by services, workers, CLI tools, desktop applications, and sidecar-style adapters.
Current customer topologies:
| Scenario | Purpose |
|---|---|
runtime/scenarios/customer-crud/spring-boot-single-process |
Spring Boot web service plus same-process runtime store target |
runtime/scenarios/customer-crud/spring-boot-starter-local |
Spring Boot starter with same-process @CoAkkaHandler targets |
runtime/scenarios/customer-crud/quarkus-local |
Quarkus Kotlin web service plus same-process runtime store target |
runtime/scenarios/customer-crud/kotlin-desktop-local |
Kotlin desktop app with two process-owned runtime handles |
runtime/scenarios/customer-crud/python-desktop-local |
Python desktop app with one process-owned RuntimeHost |
runtime/scenarios/customer-crud/spring-boot-spring-boot |
Spring Boot web service to Spring Boot store |
runtime/scenarios/customer-crud/spring-boot-node |
Spring Boot web service to Node.js store |
runtime/scenarios/customer-crud/spring-boot-go |
Spring Boot web service to Go store |
runtime/scenarios/customer-crud/spring-boot-csharp |
Spring Boot web service to C# store |
runtime/scenarios/customer-crud/spring-boot-nodes |
Spring Boot web service to Node.js store plus Node.js audit service |
Spring Boot and Quarkus samples show the same boundary inside familiar framework code: keep HTTP at the browser/API edge, and route store work as a runtime capability.
The traditional split adds a backend endpoint:
@RestController
@RequestMapping("/backend/customers")
class CustomerStoreBackendController(private val store: InMemoryCustomerStore) {
@PostMapping
fun create(@RequestBody request: CustomerDraft): MutationResponse {
return store.create(request)
}
}The browser-facing controller forwards business work through a backend HTTP client:
@RestController
@RequestMapping("/api/customers")
class CustomerController(private val storeClient: CustomerStoreRestClient) {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun createCustomer(@RequestBody request: CustomerDraft): MutationResponse {
return storeClient.create(request)
}
}That is a normal shape for a real REST boundary. For store work, the
sample instead keeps HTTP at /api/... and moves the runtime call onto a
typed runtime target.
Spring Boot uses the public starter artifact:
implementation("coakka.spring:coakka-spring-boot-starter:1.3.1-g0a0aa76")@Component
class CustomerCapabilityHandlers(private val store: InMemoryCustomerStore) {
@CoAkkaHandler("samples.customer.create")
fun create(command: CustomerDraft): MutationResponse {
return store.create(command)
}
}The controller still owns real HTTP ingress, but it asks a runtime capability rather than a backend HTTP endpoint:
@PostMapping("/api/customers")
@ResponseStatus(HttpStatus.CREATED)
fun create(@RequestBody request: CustomerDraft): MutationResponse {
return coakka.askBlocking(
"samples.customer.create",
request,
MutationResponse::class.java,
"create_customer",
5_000,
)
}Quarkus follows the same shape through the public extension artifact:
implementation("coakka.quarkus:coakka-quarkus-extension:1.3.1-g0a0aa76")@ApplicationScoped
@CoAkkaHandler("samples.customer.store")
class CustomerCapabilityHandler(...) : CoAkkaLocalHandlerRead the concrete walkthroughs here:
runtime/scenarios/customer-crud/spring-boot-starter-localruntime/scenarios/customer-crud/quarkus-local
For teams that want to see the runtime connector surface without framework
adapter help, runtime/scenarios/customer-crud/spring-boot-single-process keeps
route declaration and handler registration explicit.
coakka-runtime-client is the CLI runtime client lane. Its published command
and archive prefix is coakka-client.
If a shell reports coakka-runtime-client: command not found, use
coakka-client --help. The longer name is the product lane, not the binary.
The published CLI runtime-client release is 1.3.1+2215b0f. It lives under
coakka-publish/cli/releases/1.3.1+2215b0f/ for macOS ARM64, Linux x86_64,
Linux ARM64, Windows x86_64, and Windows ARM64. The matching Docker
verification release is under
coakka-publish/demo/coakka-client/releases/1.3.1+2215b0f/.
This lane is for native CLI verification of runtime behavior: version,
doctor, request/reply calls, ask alias behavior, and bounded script mode.
It is not a dashboard, inspect product, topology authority, or business schema
registry.
For a live request/reply path without source checkout or host build tools, run
bash run.sh runtime-client docker-bundle. That uses the published Linux
Docker verification bundle and verifies call, ask, and shell --script
against the bundled native customer service.
For a more guided Docker CLI experience, run
bash run.sh runtime-client docker-walkthrough. It starts two native runtime
services from the same published bundle, prints each service name, port, and
route, then drives both with coakka-client from a Docker CLI container.
For the Docker Hub one-command path, run
bash run.sh runtime-client dockerhub-demo or
docker run --rm docker.io/gabrielgun1983/coakka-runtime-client-demo:1.3.1-2215b0f-remote.
That image starts the native runtime services and runs coakka-client inside
one container.
Read the sample lane landing page at runtime-client/README.md.
coakka-runtime-inspect is the browser runtime explorer lane for CoAkka
Runtime. It is close to coakka-client, but visual: it renders runtime
identity, route catalog, endpoint topology, health, pressure, recent events,
and a Try Route form that can copy an equivalent coakka-client command.
Watch the runtime-inspect browser walkthrough:
Full recording: coakka-runtime-inspect.mp4
The inspect lane is not a dashboard, schema registry, service discovery server, mTLS control plane, or topology authority. Runtime core remains the source of truth; inspect reads and renders runtime facts.
Current sample status: the macOS ARM64, Linux x86_64, Linux ARM64, Windows
x86_64, and Windows ARM64 inspect archives are published in coakka-publish.
bash run.sh runtime-inspect check
bash run.sh runtime-inspect published-smoke
bash run.sh runtime-inspect local-smoke
bash run.sh runtime-inspect serve
bash run.sh runtime-inspect docker-smoke
bash run.sh runtime-inspect docker-serve
bash run.sh runtime-inspect dockerhub-smokeFor Docker, run bash run.sh runtime-inspect docker-smoke to build and smoke a
local image from the published Linux archive, or
bash run.sh runtime-inspect docker-serve to expose the browser UI on
http://127.0.0.1:18080.
For the Docker Hub zero-install path, run
bash run.sh runtime-inspect dockerhub-smoke or
docker run --rm docker.io/gabrielgun1983/coakka-runtime-inspect-sample:1.3.1-4ce41f19-remote.
Read the sample lane landing page at runtime-inspect/README.md.
The logger is the second CoAkka surface in this repository.
It is not positioned as a full replacement for SLF4J, Log4J, Logback, or each language's standard logging ecosystem. It is a bounded native logging core with small host-language connectors.
The logger samples cover:
- bounded queue capacity
- pressure rejection and dropped counters
- manual drain behavior
- native ABI/version/git diagnostics
- the same logging behavior from JVM, Python, Node.js, Go, C#, Rust, Mojo, Zig, and native C/C++
Use it when the useful property is predictable logging behavior across language ports, especially under constrained machines, queue pressure, or incident debugging.
Runtime and logger can be used independently. They are also meant to fit together in a system.
Runtime owns message routing, request/reply, one-way events, deadletters, lifecycle, and runtime diagnostics. Logger owns bounded log emission, pressure behavior, sink lifecycle, and logger diagnostics.
Together they give a service boundary both a communication contract and an observability contract. A legacy service can first adopt runtime at one integration point, then add the logger where bounded logging behavior matters, without requiring the whole application to be rewritten.
Run the default quickstart from the repository root. It checks the local toolchain and runs the smallest published JVM logger sample:
bash run.sh quickstartThe repository root command is the same quickstart:
bash run.shCheck what your machine can run without launching a sample:
bash run.sh doctorList the available samples:
bash run.sh listRun one artifact-backed sample from the repository root:
bash run.sh logger basic
bash run.sh logger node basic
bash run.sh logger native basic
bash run.sh logger zig basic
bash run.sh logger mojo basicRun public runtime native samples:
bash run.sh runtime native basic
bash run.sh runtime native pressureRun public JVM/language connector samples:
bash run.sh runtime jvm basic
bash run.sh runtime python basic
bash run.sh runtime node basic
bash run.sh runtime go basic
bash run.sh runtime csharp basic
bash run.sh runtime rust basic
bash run.sh runtime zig basic
bash run.sh runtime mojo basicRun from inside a sample directory:
cd logger/jvm/basic
bash run.shRun every sample in one lane:
bash run.sh loggerList the larger scenario tracks:
bash run.sh scenariosCheck that every scenario can build or prepare its services:
bash run.sh scenarios checkRun a scenario command from the repository root:
bash run.sh scenario customer-crud spring-boot-nodes check
bash run.sh runtime/scenarios/customer-crud/spring-boot-node smokeThe scripts create temporary install/build directories for Python, Node.js, Go, C#, Rust, Mojo, Zig, and native C/C++ package or source examples. JVM samples resolve artifacts through a Maven repository; package lanes use their ecosystem or native package archives.
If a command is missing, run bash run.sh doctor. It reports which language
lane is affected. Use COAKKA_PUBLISH_ROOT to point samples at a local public
publish checkout.
Install only the toolchain for the language you want to try:
| Language | Required locally |
|---|---|
| JVM | JDK 17 or newer |
| Python | Python 3.11 or newer with pip |
| Node.js | Node.js 20 or newer with npm |
| Go logger | Go 1.22 or newer |
| Go runtime v2 | Go 1.23 or newer |
| C# samples | .NET SDK 10 or newer |
| Rust samples | Rust/Cargo 1.74 or newer |
| Mojo logger/runtime samples | Mojo 1.0 beta or newer |
| Zig logger/runtime samples | Zig 0.16 or newer |
| Native C/C++ samples | CMake plus C and C++ compilers |
The scripts check these commands before running and print a direct error when a tool is missing.
The Kotlin JVM basic sample starts at the Level 1 connector API:
CoAkka.local(...), handler(...), and ask(...).
Most other runtime samples intentionally use the explicit start-spec shape across JVM, Python, Node.js, Go, C#, and Rust so route snapshots and diagnostics stay visible. The native C/C++, Mojo, and Zig runtime samples use the lower C ABI directly and make the same route snapshot and generation concepts visible:
Read the sample config as one startup declaration for one runtime process:
RuntimeStartSpec
this process identity
runtime queue and delivery policy
initial route table
The route table is nested:
RuntimeRouteSpec = one target/capability route
RuntimeEndpointSpec = one place that can handle that target
RuntimeEndpointFlags = endpoint state, such as LOCAL or UNAVAILABLE
| Item | Question it answers | Plain meaning |
|---|---|---|
RuntimeStartSpec |
What does this process declare when joining runtime? | Startup declaration for one runtime participant/process. |
RuntimeRouteSpec |
Which target/capability is routed where? | One route-table row: target/capability to endpoint list. |
RuntimeEndpointSpec |
Where can that target be handled? | One concrete endpoint with host, port, and flags. |
systemName |
Which logical service do I belong to? | Logical runtime participant name used in diagnostics, such as customer-store. |
nodeId |
Which concrete instance/process am I? | Concrete process identity used in logs and runtime snapshots; samples may hard-code it, but production should supply a unique value per process/pod at runtime, not bake it into the image. |
queueCapacity = 128 |
How much work can runtime buffer before applying pressure? | Bounded queue that is large enough for a sample flow but still prevents unbounded memory growth. |
strictNoDrop = true |
Should overload be visible instead of silently dropping work? | Overload becomes visible as an error/deadletter instead of silently dropping work. |
| delivered-request lane | Should runtime keep delivered requests on their own runtime lane? | Enabled by default in current connectors; it separates incoming requests this process must handle from replies/deadletters that complete asks this process already sent. |
generation = 1 |
Which version of the route table is this? | First route-table snapshot applied at startup. Real services should increment this when applying a new route snapshot. |
routes |
What targets does this runtime know how to route? | Maps a target name such as samples.customer.store to one or more endpoints. |
target |
What capability is the caller asking for? | Stable capability address, not a class name, function name, or URL. |
source |
Who is sending this request or reply? | Caller or responder identity used for diagnostics, correlation, and reply naming. |
headers |
Which request context should travel with this envelope? | Small string map for host-side context such as tenant, request id, idempotency key, or diagnostics. Business arguments should stay in payload. |
strategy |
If a target has multiple eligible endpoints, how should runtime choose one? | Route selection policy such as single owner, weighted round robin, or rendezvous hash. |
host / port |
What endpoint identity should runtime use? | Endpoint address for a process-owned listener or remote runtime handoff; samples may use 127.0.0.1, but production should read it from env, platform metadata, service discovery, or a control-plane route snapshot. Replicas of the same app role should normally share the same runtime port while host identity comes from service DNS, pod DNS/IP, or the control plane. |
RuntimeEndpointFlags.LOCAL |
Is the handler in this process? | This process owns the target and should register the handler. |
RuntimeEndpointFlags.UNAVAILABLE |
Should this endpoint stay visible but receive no new work? | Endpoint remains in the snapshot but is excluded from new route selection. |
no LOCAL flag |
Is this a peer endpoint instead of my handler? | The endpoint is a peer/remote endpoint, not a handler owned by this process. |
separateDeliveredRequestLane is mostly about protecting ask completion. A
runtime process can be doing two things at once: receiving new requests for its
local handlers, and waiting for replies or deadletters for asks it sent out.
With true, those two flows do not share the same runtime delivery lane, so a
burst of inbound handler work is less likely to delay response/deadletter
matching. With false, they share a lane; use that only for very small,
mostly one-way hosts after measurement. The samples use true as the normal
default.
The detailed runtime model
includes billing-style diagrams for the true/false cases.
Samples construct route specs directly so the runtime pieces are visible. Real integrations should usually generate route specs from config, service discovery, or a control plane. CoAkka does not remove the need to know which capability a system calls; it centralizes that knowledge in a route snapshot with generation, strategy, endpoint flags, diagnostics, and deadletters instead of scattering it across clients.
For example, a route with target = "samples.runtime.jvm.echo" and one
endpoint marked LOCAL means:
When a request targets samples.runtime.jvm.echo, deliver it to the handler
registered in this process. The 127.0.0.1:19301 address is the endpoint
identity for this runtime participant.
If the same target points to an endpoint without LOCAL, the current process
does not own the handler. Runtime treats that endpoint as a peer destination.
When sending a request, source names the caller and target names the
capability being called:
source = samples.customer.frontend
target = samples.customer.store
The runtime routes by target. source stays with the envelope so logs,
deadletters, and replies can explain who sent the work.
Parameters do not become URL path or query segments. Keep the target stable,
put business data in the typed payload, and use envelope headers only for
small request context:
target = samples.customer.hold
payload = {"customerId":"cust-001","reason":"manual_review"}
headers = {"tenant":"acme","x-request-id":"req-123"}
Customer scenarios intentionally do not include a store REST fallback. The single-process scenario can complete CRUD through a same-process runtime store target. Cross-process scenarios use the same runtime-only customer traffic across processes and languages. Only the browser-facing web surface exposes HTTP; store and audit processes are runtime handlers without a REST API.
That shape is deliberate for polyglot work. Once a store is a runtime target, changing the owner from Spring Boot to Node.js, Go, C#, Python, or another connector does not require inventing a new backend HTTP mini-service for each language.
After running the sample flows, use
Runtime Integration Guide for the
production-facing shape: dependencies, start spec, route targets, endpoint
flags, payload identities, request headers/extra parameters, handler ownership,
caller timeouts, deadletter handling, queue policy, and shutdown.
For containerized deployments, read
Containerized Runtime Notes for build-time
versus runtime identity, Kubernetes metadata supplied at startup, and nodeId
guidance.
For vocabulary such as envelope, target, route snapshot, deadletter, timeout, and delivered-request lane, see Runtime Glossary.
Language-specific entry points:
- JVM runtime samples
- Python runtime samples
- Node.js runtime samples
- Bun runtime samples
- Electron runtime samples
- Tauri runtime samples
- Go runtime samples
- C# runtime samples
- Rust runtime samples
- Mojo runtime samples
- Zig runtime samples
- Logger samples
- Native C/C++ runtime samples
CoAkka is a published runtime product surface. It is a good fit when target-based runtime delivery, payload identity, deadletters, route snapshots, and multi-language handler ownership should be part of the application model. A small system that only needs one ordinary REST or gRPC call can keep that direct shape.
For production fit, measurement checklist, learning path, and config ownership, read Production Readiness. For a stricter current-evidence ledger, read Production Evidence. For what this repository does and does not contain, read Repository Boundaries.
Android and PHP are intentionally not in the current sample matrix yet.
Bun and Electron now have public runtime package samples, and Tauri has a public source connector sample lane. Mojo and Zig have logger basic samples plus public source-package runtime lifecycle, raw request/reply, and route-miss deadletter samples. Package-manager lanes for source-package connectors remain planned; they should grow through the same FFI-based connector boundary before any framework or scenario sample claims.
Android is a likely future connector target, but it is a different kind of runtime host. The useful Android shape is not "Spring Boot on a phone"; it is a long-lived app, dashboard, field tablet, sensor surface, or edge operator UI that can own a runtime target or connect to one. That points toward an AAR packaging lane, Android lifecycle handling, foreground/background policy, ABI splits, and device smoke coverage. The Android path should start as an experiment in the connector workspace before it is presented here as a sample.
PHP is deliberately lower priority. Traditional PHP-FPM request lifecycle does
not match CoAkka's long-lived RuntimeHost model: each request is too short to
own a clean runtime lifecycle, and production FFI/native-extension policy is
often constrained by hosting and framework setup. A PHP connector, if it ever
exists, should target long-running worker hosts such as RoadRunner, Swoole, or
Laravel Octane. Generic request-per-process PHP is out of scope until there is
a clear worker-host story.
Runtime features are listed separately from language coverage so a capability does not look missing just because it is shown through one host connector first.
| Capability | Public sample | What it shows |
|---|---|---|
| Request/reply | JVM, Python, Node.js, Bun, Electron, Go, C#, Rust, native C/C++ basic samples | Typed request/reply through a process-owned route and runtime counters |
| Desktop intent bridge | Tauri and Electron intent samples | Frontend code sends intent-shaped work to the host process; Rust or Electron main owns runtime execution |
| Raw request/reply | Zig and Mojo basic samples | Raw envelope request/reply through the public C ask-client helpers and delivered-request lane |
| Runtime lifecycle/control | Zig and Mojo basic samples | Public native runtime load, route snapshot apply, start, stats read, and stop |
| Deadletter | JVM, Java, Python, Node.js, Go deadletter samples; Zig and Mojo basic route miss; native basic route miss | Missing-route accounting and matched pending requests |
| Route snapshot apply/reload | runtime/python/hot-reload; runtime/scenarios/customer-crud/spring-boot-single-process/routes.yml and runtime/scenarios/customer-crud/spring-boot-spring-boot/routes.yml with bash run.sh reload-routes |
Apply the startup route snapshot, optionally apply a newer snapshot later, reject stale/invalid snapshots, and observe generation changes |
| Queue pressure | runtime/native/pressure; status notes in runtime/README.md |
Bounded runtime queue rejection and deadletter counters at the public C ABI intake boundary |
| Logger basic | Mojo and Zig basic samples; JVM, Java, Python, Node.js, Go, C#, Rust, and native logger basic samples | One bounded logger record through the public logger contract |
| Logger pressure | JVM, Java, Python, Node.js, Go, C#, Rust, native logger pressure samples | Bounded logger queue rejection and dropped counters |
| Customer CRUD scenarios | Spring Boot, Quarkus, desktop, Node.js, Go, and C# scenario tracks | Real workflow shape across same-process and cross-process runtime boundaries |
Current gaps:
| Gap | Status |
|---|---|
| Cross-process route apply/reload scenario | Route apply covered by runtime/scenarios/customer-crud/spring-boot-spring-boot/routes.yml; live cross-host delivery capture pending |
| Language connector runtime pressure samples | Tracked separately from native intake pressure; pinned connector samples cover request/reply, deadletter, and route snapshot apply/reload |
| Two-machine Linux walkthrough | Manual setup documented in docs/two-machine-linux.md; live two-host capture pending |
| Repeatable benchmark harness | Manual smoke-load harness present; Linux CI workflow is manual; Linux hardware benchmark remains pending |
Containerized samples are the low-friction public path. The current refreshed target is a lightweight Node.js web UI calling a Python customer store through the CoAkka runtime.
Run the wave 1 sample:
bash run.sh containers node-pythonThen open:
http://localhost:8080
http://localhost:8081
Stop all container samples:
bash run.sh containers downOr run Compose directly:
docker compose -f containers/node-python/compose.yaml up
podman compose -f containers/node-python/compose.yaml up
podman-compose -f containers/node-python/compose.yaml upThe intent is to show two real processes, two language hosts, and one runtime
delivery path with browser-visible state changes. The Spring Boot JVM to Go
container lane remains a compose skeleton until its image-source path is
refreshed onto the same 1.3.1 runtime line; the Spring-Go source scenario is
the supported framework path for this train.
Framework native-image builds are deliberately not the primary public sample path. For Java and Kotlin framework applications, the JVM remains the expected runtime: it keeps the normal dependency model, diagnostics, profiling, and steady-state behavior. For native deployment, the sample matrix uses native language hosts such as Go, Rust, C, and C++ instead of treating native-image as the default way to run Spring Boot or Quarkus.
Spring Boot native-image and Quarkus native-image may be explored later as optional advanced lanes if they become useful for a concrete deployment case, but they are not a promise or a requirement for the container story.
The default container path uses pinned Docker Hub images so users can try a runtime generation without building connector packages, transport dependencies, or native runtime artifacts locally.
Those Docker images are convenience wrappers around published CoAkka artifacts.
They are not the primary release location; use coakka-publish for direct
artifact downloads and checksums.
Planning note: Container Samples Plan.
| Lane | JVM | Python | Node.js | Bun | Electron | Tauri | Go | C# | Rust | Mojo | Zig | Native C/C++ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Runtime v2 basic | runtime/jvm/basic, runtime/jvm/java-basic |
runtime/python/basic |
runtime/node/basic |
runtime/bun/basic |
runtime/electron/basic |
runtime/tauri/intent-command |
runtime/go/basic |
runtime/csharp/basic |
runtime/rust/basic |
runtime/mojo/basic |
runtime/zig/basic |
runtime/native/basic |
| Runtime v2 desktop intent | - | - | - | - | runtime/electron/basic |
runtime/tauri/desktop-intent |
- | - | - | - | - | - |
| Runtime v2 deadletter | runtime/jvm/deadletter, runtime/jvm/java-deadletter |
runtime/python/deadletter |
runtime/node/deadletter |
- | - | - | runtime/go/deadletter |
- | - | - | - | - |
| Runtime v2 pressure | - | - | - | - | - | - | - | - | - | - | - | runtime/native/pressure |
| Logger basic | logger/jvm/basic, logger/jvm/java-basic |
logger/python/basic |
logger/node/basic |
- | - | - | logger/go/basic |
logger/csharp/basic |
logger/rust/basic |
logger/mojo/basic |
logger/zig/basic |
logger/native/basic |
| Logger pressure | logger/jvm/pressure, logger/jvm/java-pressure |
logger/python/pressure |
logger/node/pressure |
- | - | - | logger/go/pressure |
logger/csharp/pressure |
logger/rust/pressure |
- | - | logger/native/pressure |
This repository keeps benchmark files as reference evidence. macOS results are useful for shape checks and local regression comparison on the same machine. Linux results are the comparison path to prefer when readers want a broader view of runtime behavior.
Benchmark results are not the primary positioning for CoAkka, even when the runtime path has practical advantages. The product argument is about changing the boundary model first; numbers are there to validate regressions and deployment profiles after that model is understood.
Benchmark comparisons should stay at CoAkka's runtime/L4 boundary: route lookup, bounded admission, framing, delivery outcome, and reply matching. Do not frame these numbers as L7 HTTP/gRPC replacement benchmarks; HTTP and gRPC belong at service API edges with different middleware, semantics, and tooling. If no same-class runtime comparator exists, use benchmarks for CoAkka release regression and deployment-profile evidence instead of forcing an uneven protocol comparison.
Benchmark and load result policy lives in bench/README.md.
The harness keeps macOS reference output under bench/macos-smoke/ and Linux
runner output under bench/linux-ci/ so readers can separate local guardrails
from Linux runner evidence.
The current harness is manual:
python3 bench/run_smoke_load.py --profile runtime-native-pressure
python3 bench/run_smoke_load.py --profile runtime-python-hot-reload
python3 bench/validate_smoke_load.py bench/linux-ci/<commit>-<profile>.jsonThe bench-smoke GitHub Actions workflow uses the same JSON format on
ubuntu-latest when triggered through workflow_dispatch. It validates the
JSON artifact before upload so Linux CI evidence fails closed if the profile
does not emit the expected diagnostics.
Repository layout:
runtime/
jvm/
basic/
java-basic/
deadletter/
java-deadletter/
python/
basic/
deadletter/
hot-reload/
node/
basic/
deadletter/
go/
basic/
deadletter/
csharp/
basic/
rust/
basic/
mojo/
basic/
zig/
basic/
native/
basic/
pressure/
scenarios/
customer-crud/
logger/
jvm/
basic/
java-basic/
pressure/
java-pressure/
python/
basic/
pressure/
node/
basic/
pressure/
go/
basic/
pressure/
csharp/
basic/
pressure/
rust/
basic/
pressure/
mojo/
basic/
zig/
basic/
native/
basic/
pressure/
Public artifact downloads are owned by
coakka-publish, not by this
sample repository. That repository contains logger package downloads, the
public native runtime C ABI package, runtime connector packages, framework
adapters, the coakka-runtime-client CLI lane, release notes, manifests, and
checksums.
The sample runner resolves public artifacts from a sibling coakka-publish
checkout when present, then falls back to the public raw GitHub URL:
https://raw.githubusercontent.com/phuong-tran/coakka-publish/main/
Logger JVM samples use the Maven repository from the public publish checkout:
repositories {
mavenCentral()
maven {
url = uri("/path/to/coakka-publish/maven")
}
}
dependencies {
implementation("coakka.logger:coakka-jvm-native-logger:1.2.1-gf50756ebff0d")
}For local development, the root Gradle build checks a sibling
coakka-publish Maven directory first:
workspace-root/
coakka-publish/maven/
coakka-samples-public/
Override the local Maven repository path with:
COAKKA_PUBLISH_MAVEN_LOCAL=/path/to/coakka-publish/maven bash run.sh loggerPython, Node.js, Go, C#, Rust, native C/C++, Mojo, Zig, and non-Maven package
lanes first look for a sibling coakka-publish checkout. Use
COAKKA_PUBLISH_ROOT to point samples at another public artifact checkout:
COAKKA_PUBLISH_ROOT=/path/to/coakka-publish bash run.sh logger
COAKKA_PUBLISH_ROOT=/path/to/coakka-publish bash run.sh runtime native basic
COAKKA_PUBLISH_ROOT=/path/to/coakka-publish bash run.sh runtimePublic package downloads are pinned through
coakka-publish/artifacts/public-artifacts.tsv. When a sample resolves
an artifact from the local public checkout or from the public raw GitHub URL, it
verifies the artifact SHA256 from that manifest before unpacking or installing
the package.
Docker samples follow the same ownership rule. Docker Hub image tags provide a ready-to-run sample path, while the runtime and connector artifacts bundled by those images are still sourced from the public publish surface.
The sample artifact-pin smoke validates manifest rows by default. The heavier
local coakka-publish surface gate is opt-in:
COAKKA_PIN_CHECK_PUBLISH_GATE=1 bash scripts/check-artifact-pins.shPinned public artifact lines used by these samples:
| Lane | Release |
|---|---|
| Logger JVM | coakka.logger:coakka-jvm-native-logger:1.2.1-gf50756ebff0d |
| Logger Python, Node.js, Go, C#, Rust, Mojo, Zig, and native C/C++ | 1.2.1+f50756ebff0d |
| Runtime native C/C++ | 1.3.1+bda2ef5 |
| Runtime JVM | coakka.v2:coakka-jvm-native-runtime-v2:1.3.1-gbda2ef5-0a0aa76 |
| Runtime Python, Node.js, and Go | 1.3.1+bda2ef5-0a0aa76 |
| Runtime Bun and Tauri samples | 1.3.1+bda2ef5-247df1b |
| Runtime Electron sample | 1.3.1+bda2ef5-4e0cab0 |
| Runtime C# | 1.3.1+bda2ef5-0a0aa76 |
| Runtime Rust | 1.3.1+bda2ef5-0a0aa76 |
| Runtime Mojo and Zig samples | 1.3.1+bda2ef5-0a0aa76 source packages |
| Runtime CLI client | coakka-runtime-client lane, coakka-client command, 1.3.1+2215b0f |
| Runtime inspect | 1.3.1+4ce41f19 Linux x86_64/ARM64 archives; 1.3.1+d7ab7fa macOS ARM64 and Windows x86_64/ARM64 archives |
| Spring Boot starter | coakka.spring:coakka-spring-boot-starter:1.3.1-g0a0aa76 |
| Quarkus extension | coakka.quarkus:coakka-quarkus-extension:1.3.1-g0a0aa76 |
The matching runtime native note is published at
https://github.com/phuong-tran/coakka-publish/blob/main/docs/releases/2026-07-18-runtime-native-1.3.1-bda2ef5.md.
The matching runtime JVM note is published at
https://github.com/phuong-tran/coakka-publish/blob/main/docs/releases/2026-07-18-runtime-jvm-1.3.1-0a0aa76.md.
The matching non-JVM connector note is published at
https://github.com/phuong-tran/coakka-publish/blob/main/docs/releases/2026-07-18-runtime-non-jvm-1.3.1-0a0aa76.md.
The matching Spring Boot and Quarkus adapter note is published at
https://github.com/phuong-tran/coakka-publish/blob/main/docs/releases/2026-07-18-runtime-jvm-adapters-1.3.1-0a0aa76.md.
Pinned runtime connector/native generation: 1.3.1+bda2ef5.
Published runtime-client CLI generation: 1.3.1+2215b0f.
Runtime inspect public artifact: 1.3.1+4ce41f19 for Linux x86_64/ARM64 and
1.3.1+d7ab7fa for macOS ARM64 and Windows x86_64/ARM64.
| Lane | Public artifact status | First command |
|---|---|---|
| Logger JVM | public | bash run.sh logger basic |
| Logger Python | public | bash run.sh logger python basic |
| Logger Node.js | public | bash run.sh logger node basic |
| Logger Go | public | bash run.sh logger go basic |
| Logger C# | public | bash run.sh logger csharp basic |
| Logger Rust | public | bash run.sh logger rust basic |
| Logger native C/C++ | public | bash run.sh logger native basic |
| Runtime native C/C++ | public | bash run.sh runtime native basic |
| Runtime JVM | public | bash run.sh runtime jvm basic |
| Runtime Python | public | bash run.sh runtime python basic |
| Runtime Node.js | public | bash run.sh runtime node basic |
| Runtime Bun | public | bash run.sh runtime bun basic |
| Runtime Electron | public | bash run.sh runtime electron basic |
| Runtime Tauri | public source sample | bash run.sh runtime tauri intent-command |
| Runtime Go | public | bash run.sh runtime go basic |
| Runtime C# | public | bash run.sh runtime csharp basic |
| Runtime Rust | public | bash run.sh runtime rust basic |
| Runtime CLI client | public | bash run.sh runtime-client |
| Runtime inspect | public macOS ARM64, Linux x86_64/ARM64, and Windows x86_64/ARM64 archives, local/native fallback, local Docker image wrapper | bash run.sh runtime-inspect check |
| Logger Mojo | source sample | bash run.sh logger mojo basic |
| Logger Zig | source sample | bash run.sh logger zig basic |
| Runtime Mojo | source sample | bash run.sh runtime mojo basic |
| Runtime Zig | source sample | bash run.sh runtime zig basic |
| Runtime Spring Boot and Quarkus adapters | public | bash run.sh scenarios check |
| Runtime container sample: Node.js -> Python | public Docker Hub images | bash run.sh containers node-python |
Samples resolve public downloads through
coakka-publish/artifacts/public-artifacts.tsv or the matching public
raw GitHub URL and verify SHA256 before unpacking or installing an artifact.
Runtime language and framework samples in this status table are aligned to the
same native package generation unless a later release note declares otherwise.
Runtime language/framework direct runs consume the public runtime artifacts:
./gradlew :runtime:jvm:basic:run
./gradlew :runtime:jvm:java-basic:runExpected output shape:
coakka_runtime_info abi=1 version=1.3.1 git=<git>
coakka_runtime_response payload={"echo":"hello-runtime-jvm"}
coakka_runtime_stats generation=1 routes=1 delivered=1 matchedResponses=1
The JVM runtime lane includes both Kotlin and Java entrypoints. The Java basic
sample prints the same flow with language=java:
coakka_runtime_response payload={"echo":"hello-runtime-java"}
coakka_runtime_stats generation=1 routes=1 delivered=1 matchedResponses=1 language=java
Run the runtime v2 samples:
bash run.sh runtimeRun the C# runtime package smoke directly:
bash run.sh runtime csharp basicRun the native C/C++ runtime v2 sample directly:
bash run.sh runtime native basicExpected output shape:
coakka_runtime_info abi=1 version=1.3.1 git=<git> language=c
coakka_runtime_stats generation=1 routes=1 routeMisses=1 deadletters=1 language=c
coakka_runtime_info abi=1 version=1.3.1 git=<git> language=cpp
coakka_runtime_stats generation=1 routes=1 routeMisses=1 deadletters=1 language=cpp
Run the native runtime pressure sample directly:
bash run.sh runtime native pressureExpected output shape:
coakka_runtime_info abi=1 version=1.3.1 git=<git> language=c
coakka_runtime_pressure attempts=64 delivered=<n> rejected=<n> capacity=2 highWatermark=<n> language=c
coakka_runtime_stats generation=1 routes=1 queueRejected=<n> deadletters=<n> language=c
The runtime lane also includes deadletter samples that send one request to a missing route, observe the deadletter stream, and verify route-miss accounting:
coakka_runtime_deadletter reason=DEADLETTER_REASON_ROUTE_MISS target=samples.runtime.jvm.deadletter.missing generation=1
coakka_runtime_deadletter_observed matchedPending=true target=samples.runtime.jvm.deadletter.missing
coakka_runtime_stats routeMisses=1 deadletters=1 matchedDeadletters=1
Run the smallest JVM logger sample directly through Gradle:
./gradlew :logger:jvm:basic:run
./gradlew :logger:jvm:java-basic:runExpected output shape:
coakka_logger_info abi=10 version=1.2.1 git=<git>
coakka_logger_record sequence=1 level=info category=samples.logger.jvm.basic message={"event":"hello","language":"jvm"}
coakka_logger_stats emitted=1 delivered=1 dropped=0
The JVM logger lane also includes Java basic and pressure samples:
./gradlew :logger:jvm:java-basic:run
./gradlew :logger:jvm:java-pressure:runThe exact sequence number can change if the sample is extended.
Run every published logger sample across JVM, Python, Node.js, Go, C#, Rust, Mojo, Zig, and native C/C++:
bash run.sh loggerThe logger lane also includes pressure samples that fill a queue with capacity
2 and verify rejected writes are counted as dropped:
coakka_logger_pressure attempts=8 accepted=2 rejected=6 capacity=2 highWatermark=2
coakka_logger_stats emitted=2 delivered=2 dropped=6
Check the customer scenario services without keeping servers running:
bash run.sh scenarios checkRun one scenario check directly:
bash run.sh runtime/scenarios/customer-crud/spring-boot-spring-boot
bash run.sh runtime/scenarios/customer-crud/kotlin-desktop-local smoke
bash run.sh runtime/scenarios/customer-crud/python-desktop-local smokeThe default command for each scenario is check, so opening a scenario
run.sh from a shell still performs a real build/preparation step. Long-running
scenario commands such as web, store, and audit start services and should
be run in separate terminals. dev builds and starts the whole topology from
one shell. Local desktop/single-process scenarios and cross-process customer
scenarios all keep customer traffic on the runtime path and avoid a store REST
fallback.
GitHub Actions currently runs a public surface check. It verifies script syntax, Python/Node sample syntax, sample listing, artifact pins, selected logger package smoke samples, and selected runtime smoke samples.
If native loading fails, first check:
- the selected publish repo path
- the relevant
manifest.jsonunder the local publish checkout - Runtime v2 JVM/Python/Node.js/Bun/Electron/Go/C#/Rust samples consume language artifacts that bundle or resolve the supported-platform native runtime; no separate per-platform native download is required for normal sample use.
- Logger JVM/Python/Node.js/Go/C#/Rust samples use all-in-one language artifacts for supported platforms.
- Tauri, Mojo, and Zig runtime samples use public source connector packages with bundled native runtime libraries.
- Mojo and Zig logger samples use the published native logger archive.
- Native C/C++ samples use the published native archive and select the current platform with CMake.
- whether the current OS/architecture is one of:
macos-aarch64linux-aarch64linux-x86_64
The JVM logger jar also accepts an explicit native override:
./gradlew :logger:jvm:basic:run -Dcoakka.logger.lib=/abs/path/to/libcoakka_logger_core.dylibThe sample code, scripts, and documentation in this repository are licensed under the Apache License, Version 2.0. See NOTICE for the repository notice.
Runtime binaries, connector packages, Maven artifacts, and other released
artifacts consumed by these samples come from coakka-publish and are
covered by the license terms in that artifact repository or the terms included
with the specific release artifact.
The CoAkka name and coakka package, artifact, and image prefixes identify
the official project surface. See TRADEMARKS.md before using
the name for forks, derived samples, hosted services, or product branding.



