name: bassline
description: Work with Bassline: a programming environment for reflexive distributed systems. Use Bassline when you want to make p2p connections with a simple API, build propagation networks, use a TCL with state serialization or manage agents in distributed settings.
license: AGPL-3.0
compatibility: Requires @bassline packages installed in the project
Bassline
Everything in Bassline is a resource with two operations:
await resource.get(headers)
await resource.put(headers, body)
Semantic Addressing
Everything in Bassline is semantically addressed. Resources don't have a single concrete identity—instead they exist relative to other resources.
Routers are resources that delegate interactions by dispatching based on information in the headers. Paths are just a common example of semantic routing information. This lets us talk about resources as though we were interacting with a file-system.
const result = await resource.get({ path: '/cells/counter/value' })
const result = await resource.put({ path: '/store/users/alice' }, { name: 'Alice' })
Paths route segment by segment:
/cells/counter/value → cells → counter → value
/store/users/alice → store → users → alice
You are free to choose whatever dispatch logic makes sense in your domain.
Response Format
Every operation returns { headers, body }:
{ headers: {}, body: { name: 'Alice' } }
{ headers: { type: '/types/cell' }, body: { lattice: 'maxNumber', value: 5 } }
{ headers: { condition: 'not-found' }, body: null }
{ headers: { condition: 'error', message: 'Something went wrong' }, body: null }
Always check for conditions:
const result = await kit.get({ path: '/cells/counter/value' })
if (result.headers.condition === 'not-found') {
}
if (result.headers.condition === 'error') {
console.error(result.headers.message)
}
The Kit Rule
A kit is simply a resource passed via headers.
When a resource needs flexible or dynamic access to other resources that it doesn't know about ahead of time, it can do so with a kit. This makes kits a form of dependency injection for resources.
const worker = resource({
put: async (h, task) => {
const { body: config } = await h.kit.get({ path: '/config' })
await h.kit.put({ path: '/results/latest' }, result)
return { headers: {}, body: { done: true } }
},
})
When a resource delegates to another resource, it can provide an alternative kit to change the effective "world" a resource is interacting in. Same resource, different kit = different capabilities.
Because resources don't have concrete identities, kits can work over network boundaries. When interacting with a kit that is located on an external machine, we can simply proxy interactions through another local resource we create.
Creating Resources
Basic Resource
import { resource } from '@bassline/core'
let count = 0
const counter = resource({
get: async h => ({ headers: {}, body: count }),
put: async (h, b) => {
count = b
return { headers: {}, body: count }
},
})
Routing by Path
import { routes } from '@bassline/core'
const app = routes({
cells: cellsResource,
store: storeResource,
fn: fnResource,
unknown: fallbackResource,
})
Capturing Path Parameters
import { bind } from '@bassline/core'
const users = bind(
'id',
resource({
get: async h => {
const userId = h.params.id
},
})
)
Quick Reference
| Resource | Create | Read | Write |
|---|
| Cell | PUT /cells/name { lattice: 'maxNumber' } | GET /cells/name/value | PUT /cells/name/value <value> |
| Store | (auto-created) | GET /store/path/to/key | PUT /store/path/to/key <value> |
| Propagator | PUT /propagators/name { inputs, output, fn } | GET /propagators/name | PUT /propagators/name/run |
| Function | PUT /fn/name <function> | GET /fn/name | - |
Packages
Bassline is split into focused packages. See the reference files for detailed usage:
| Package | Purpose | Reference |
|---|
@bassline/core | Resources, types, stores, propagators, functions | core.md |
@bassline/blit | SQLite-backed persistent applications | blit.md |
@bassline/tcl | TCL scripting for boot scripts and automation | tcl.md |
@bassline/database | SQLite database connections and queries | database.md |
@bassline/services | Claude API integration and agentic loops | services.md |
@bassline/trust | Trust computation and capability gating | trust.md |
When to Use Each
- Building state that merges → cells with lattices (
core.md)
- Storing key/value data → store (
core.md)
- Reactive computation → propagators (
core.md)
- Persisting an application → blits (
blit.md)
- Writing boot/init scripts → TCL (
tcl.md)
- Direct SQL access → database (
database.md)
- LLM-powered features → services (
services.md)
- Peer trust/capabilities → trust (
trust.md)