npm stats
  • Search
  • About
  • Repo
  • Sponsor
  • more
    • Search
    • About
    • Repo
    • Sponsor

Made by Antonio Ramirez

bareclaw

0.1.1

@GitHub Actions

npmHomeRepoSnykSocket
Downloads:11
$ npm install bareclaw
DailyWeeklyMonthlyYearly

bareclaw

bareclaw

picoclaw — the Go AI agent — wrapped as a Bare library, spoken to entirely over RPC.
State lives in a Hyperbee. The Go side never touches your terminal.

🐻 A Claude experiment. Built by Claude (Opus 4.8), spelunking the Holepunch + picoclaw stack.


What is this?

bareclaw takes picoclaw (a capable, multi-provider AI agent written in Go) and exposes it as a clean, embeddable Bare module.

The trick: the Go agent is compiled to a small binary, spawned as a subprocess, and driven purely over bare-rpc across stdio using compact-encoding frames. From JavaScript you get a tidy async/streaming API; under the hood it's a Go agent loop.

Sessions and conversation history are persisted into a Hyperbee on the Bare side. The Go process is the stateless engine; the bee is the source of truth. Pass it a Corestore and it does the rest.

┌────────────────────────┐        bare-rpc over stdio         ┌──────────────────────┐
│  Bareclaw (JS / Bare)  │  ─── compact-encoding frames ───▶  │  picoclaw (Go binary)│
│  • Hyperbee state      │  ◀── tool calls / chat stream ───  │  • agent loop        │
│  • tool handlers (JS)  │                                    │  • LLM providers     │
└────────────────────────┘                                    └──────────────────────┘

Install

npm install

Prebuilt Go binaries for darwin/linux/win32 × x64/arm64 ship in prebuilds/ (resolved via the #bareclaw import map). To rebuild them yourself:

make build            # cross-compile all targets into prebuilds/
# or a single host build:
go -C go build -o ../prebuilds/darwin-arm64/bareclaw ./cmd

You'll also need an LLM the agent can reach — e.g. a local Ollama (ollama run llama3.2) or an API key for Anthropic/OpenAI/etc.

Quick start

const Corestore = require('corestore')
const { Bareclaw } = require('bareclaw')

const store = new Corestore('./store')
await store.ready()

// All Go options are passed via `opts`.
const bc = new Bareclaw(store, { provider: 'ollama', model: 'llama3.2' })
await bc.ready()

// Sessions are keyed deterministically from their scope.
const key = await bc.session({ agentId: 'assistant', channel: 'general' })

// chat() yields structured, string-typed chunks.
for await (const chunk of bc.chat(key, 'Say hello in one word.')) {
  if (chunk.type === 'content') process.stdout.write(chunk.content)
  if (chunk.done) break // 'done' (or 'error') is a pure terminator
}

await bc.close() // flushes state to the bee, stops Go cleanly

Run the included demo with bare example.js.

API

new Bareclaw(store, opts = {})

store is a Corestore (the library opens its own Hyperbee on it). Everything Go needs comes through opts:

optiontypenotes
providerstringe.g. ollama, anthropic, openai
modelstringe.g. llama3.2, claude-... (sets picoclaw model_name + model)
apiKeystringfor hosted providers
apiBasestringcustom endpoint
configobject | stringinline picoclaw config (merged over defaults) — or a path to a config file
builtinToolsbooleankeep picoclaw's built-in OS tools (default off — see below)

Tools. By default a bareclaw agent has no built-in tools — its tools come from registerTool. picoclaw's built-in OS tools (file/exec/skills) act on the Go process, not your app, and make small models emit tool-call noise, so they're off unless you pass builtinTools: true.

await bc.session(scope = {})

Returns a deterministic string key for a scope ({ agentId, channel, account, peer }). Same scope → same key. Records the session in the bee so it's listed and survives restarts.

await bc.sessions()

Lists known session keys — read straight from the bee.

bc.chat(sessionId, message, opts = {}) → async iterable

Yields chunks shaped like:

{ type: 'content',  content: '…', done: false }   // streamed / final text
{ type: 'thinking', content: '…', done: false }   // reasoning (when available)
{ type: 'done',  done: true }                      // terminator, no body
{ type: 'error', content: '…', done: true }        // terminator with message

opts.model overrides the model for a single turn. After each turn the session's history is persisted into the bee automatically.

await bc.exportSession(key) → Buffer

Opaque blob of a session's history + summary.

await bc.importSession(key, blob)

Restores a session (into both Go and the bee). Round-trips with exportSession.

await bc.registerTool(name, description, schema, handler)

Registers a JavaScript tool the Go agent can call. schema is JSON Schema; handler(input) returns the result. The agent invokes it via an RPC callback:

await bc.registerTool(
  'reverse',
  'Reverse a string',
  { type: 'object', properties: { text: { type: 'string' } }, required: ['text'] },
  async ({ text }) => ({ result: [...text].reverse().join('') })
)

await bc.close()

Flushes each session's final state to the bee, then shuts the Go process down gracefully (closes its stdin so it reaches EOF and exits).

What's possible

  • Embed a full agent loop in any Bare app — desktop, mobile, P2P — with no Node, no servers, no terminal noise.
  • P2P-native state. Because sessions live in a Corestore/Hyperbee, they replicate, sync, and persist like any other Holepunch data structure.
  • JS-defined tools executed by a Go agent — bridge the agent to anything in your Bare runtime.
  • Bring your own model — local (Ollama) or hosted — selected entirely through opts.

Examples

Runnable P2P demos live in examples/ (each is bare examples/<file>):

demowhat it shows
swarm-collab.jstwo agents discover each other on a Hyperswarm topic and collaborate by relaying turns
peer-scan-tool.jsa registerTool P2P tool — the agent joins a swarm, counts peers, and leaves
dht-shared.jsa HyperDHT server as a one-to-many hub: agents post ideas, the merged board fans back to all
swarm-code-review.jsa multi-agent code-review panel with consensus — 2 agents per lens (to see agreement), a correlator weighs findings over the DHT, verdict written to review.md

See examples/README.md for details.

Testing

npm test          # brittle-bare test/all.mjs

Session/state tests run without an LLM. Chat and tool tests need a reachable model (the helpers default to ollama + llama3.2).

Known limitations / what's missing

This is an experiment — here's what's rough or unfinished, honestly:

  • Streaming isn't token-by-token (yet). picoclaw's streaming path isn't engaged for the Ollama provider in this RPC setup, so a reply usually arrives as a single content frame rather than incrementally. The thinking chunk type is wired but rarely emitted.
  • Small local models are noisy. Built-in tools are off by default (which removes most tool-call-JSON noise), but tiny models like llama3.2 can still spontaneously emit function-call-shaped JSON or ramble. Use a capable model/provider for sharp, reliable output and real tool use.
  • Go still writes its own session JSONL to disk. The bee is the bare-side source of truth, but picoclaw's internal store also persists to ~/.picoclaw (or the configured dir). Fully routing that through the bee is future work.
  • Live state-change events aren't fired. The CMD_STATE_CHANGED push path exists but Go doesn't emit it yet; persistence happens after each chat turn and on close() instead.
  • Whole-session blobs. Each persist rewrites a session's full blob rather than appending deltas — fine for chats, wasteful for very long histories.
  • No auth/sandboxing of JS tools. Registered tools run with full Bare privileges.

Credits

  • picoclaw — the Go AI agent doing the real work.
  • Bare + bare-rpc + Hyperbee — the Holepunch runtime and primitives.
  • 🤖 Wired together by Claude as an experiment in bridging a Go agent into the Bare world.