Forge
Local Go ↔ Rust worker IPC: length-prefixed frames, MessagePack or JSON, control-plane RPCs (ping, health, capabilities, shutdown, cancel_job, job_status), and optional progress events.
This directory is the framework used by products such as Organizy (organizy/daemon + organizy-worker). It stays domain-agnostic.
Framework boundary: Forge owns framing, transport, and worker lifecycle — not product schemas, storage, or scheduling.
Layout
| Path | Contents |
|---|---|
go/ |
Go module github.com/organizyio/forge/go — package forge: Conn, Client, WorkerProcess, Pool, ExtractEmbedded, ChannelEventBus |
rust/ |
Cargo workspace: forge-worker-sdk crate at rust/forge-worker-sdk/ (no crates/ nesting), examples/minimal-worker |
protocol/ |
Version VERSION, JSON fixtures, spec.md, tools/gen_spec.py |
docs/ |
forge-implementation-spec.md, worker-framework-reference.md, go-client.md, rust-worker.md |
scripts/ |
release.sh (pre-tag checks), gen-fixtures.sh (regenerate protocol/spec.md from fixtures + run contract tests) |
Installation
Rust: add forge-worker-sdk from this repo (path or git) or from crates.io once published. Import as forge_worker_sdk in code.
Getting started (real APIs)
Rust worker
From forge/rust:
Implement forge_worker_sdk::WorkerHandler; use forge_worker_sdk::run_worker with your handler and Encoding. See forge-worker-sdk crate docs and examples/minimal-worker/src/main.rs.
Go supervisor
import (
"context"
forge "github.com/organizyio/forge/go"
)
conn, err := forge.Dial(ctx, "/tmp/forge-minimal.sock", forge.EncodingJSON, func(ev *forge.Event) )
if err != nil
defer conn.Close()
client := forge.NewClient(conn)
if _, err := client.Ping(ctx); err != nil
st, err := client.JobStatus(ctx, "job-1") // decodes state, job_id, progress, error
Windows named pipe (Rust worker listening on a pipe): dial with a pipe address, e.g. \\.\pipe\YourPipeName or //./pipe/YourPipeName.
Spawn + supervise a worker binary (Unix: default socket under SocketDir; Windows pipe: set SocketPath to e.g. \\.\pipe\YourPipeName and pass the same value as the worker’s --socket):
wp := forge.NewWorkerProcess(1, forge.WorkerConfig)
if err := wp.Start(ctx); err != nil
defer wp.Stop(ctx)
c := wp.Client()
_, _ = c.Ping(ctx)
Build & test
# Go (from forge/go)
# Rust (from forge/rust)
On Windows, use the MSVC Rust toolchain for cargo test if GNU MinGW is incomplete (rustup default stable-x86_64-pc-windows-msvc or an override in forge/rust). See rust/README.md.
CI
GitHub Actions runs path-scoped jobs for go/, rust/, protocol/, and shared integration tests. The required check to gate merges is the aggregate job CI (see .github/workflows/ci.yml).
Releases and versioning
release.yml can run in three ways:
- workflow_dispatch — Actions → Release → Run workflow; enter a version (e.g.
1.2.0withoutv). - After CI on
main/master— when the CI workflow completes successfully on a push, the patch version is auto-incremented from the latestv*tag (skipped ifHEADis already tagged). This runs on every successful CI run on the default branch; disable or adjust theworkflow_runtrigger inrelease.ymlif you want releases only when you dispatch them manually. - Manual tag —
git tag v0.1.0 && git push origin v0.1.0runs GoReleaser only (no changelog commit).
On paths (1) and (2), the workflow verifies the repo, prepends to CHANGELOG.md, refreshes the Go version badge in this README from go/go.mod, bumps rust/forge-worker-sdk/Cargo.toml, commits, pushes the branch, creates the tag, runs GoReleaser, and notifies proxy.golang.org. Prefer conventional commits (feat:, fix:, chore:, …) so changelog sections populate.
Optional: publish forge-worker-sdk to crates.io
Follow Publishing on crates.io: create an API token on crates.io, then add it as a GitHub Actions repository secret named CARGO_REGISTRY_TOKEN. Cargo reads that token from the environment variable of the same name (credentials / CARGO_REGISTRY_TOKEN).
- Set repository variable
PUBLISH_TO_CRATES_IOtotrue. - Add secret
CARGO_REGISTRY_TOKEN(the crates.io API token). - The release workflow runs
cargo publish -p forge-worker-sdk --lockedafter GoReleaser when the variable is set.
Specification
- Wire format & RPC tables:
protocol/spec.md(includes generated sections from fixtures +go doc). - Implementation truth:
docs/forge-implementation-spec.md.