Skip to main content

Koshmana client

The client for Koshmana — a hypermedia, event-sourced data service living at https://koshmana.com. One small library, one CLI, one MCP server; no server code. If you are an agent who just landed on koshmana.com, this is how you talk to it.

What Koshmana is (the model in 60 seconds)

  • The log is truth. Everything is an activity (Activity Streams 2.0 JSON — Create, Update, Delete, …) appended to a collection. The append is the commit; the ack's sequence is the event's permanent position on the log. Nothing is ever edited or removed from the log — you change state by appending more activities.
  • Reads are projections. A read model folds the log into current state. Every read answer carries koshmana:watermark (how far behind truth the projection is). Pass an append ack's sequence back as min_sequence for read-your-writes.
  • Objects are dereferenceable URLs. An object's id resolves to its current state (GET /collections/{coll}/objects/{id}). On deployments with a public URL the id is an HTTPS URL you can GET directly.
  • Reads can be public; representations are content-negotiated. A collection declared public: true serves its objects to anyone with no bearer and Access-Control-Allow-Origin: *. Both object read doors are content-negotiated: Accept: text/html renders via the collection's template (if any); otherwise you get AS2 JSON. Writes always stay authenticated.
  • A collection can be a website. Declare site: true and its objects become files addressed by path; /{project}/{coll}/… serves them like a web server, and a deploy is just a batch of appends.

Install

pip install koshmana            # library + `koshmana` CLI
pip install "koshmana[mcp]"     # also the `koshmana-mcp` MCP server

Requires Python 3.13+. Runtime deps are tiny: httpx and pyyaml (plus mcp only for the optional MCP server).

Configuration — three environment variables

Env var CLI flag Default
Server KOSHMANA_URL --url http://127.0.0.1:8600
Token KOSHMANA_TOKEN --token dev-write-token
Actor KOSHMANA_ACTOR --actor (per command) https://koshmana.dev/actors/cli

To talk to production, set KOSHMANA_URL=https://koshmana.com, a real KOSHMANA_TOKEN, and a KOSHMANA_ACTOR that identifies you (every write's envelope actor must equal the actor your token is bound to). Reads on public collections need no token.

CLI quickstart

Output is YAML by default; add --json to see the exact wire format. Global flags (--url, --token, --json) work before or after the subcommand.

koshmana collections                          # what collections exist here
koshmana describe issues                      # a collection's full declaration
koshmana bindings journal                     # a collection's materialized bindings

# Read a declared read model (default entry: "recent")
koshmana get issues
koshmana get issues --slice by-status open    # a computed slice
koshmana get issues --where status=open --where priority=high
koshmana get issues --search '"exact phrase" -noise'
koshmana get issues --order priority --descending

# Append an activity (the commit). YAML or JSON, file or stdin.
koshmana append issues -f issue.yaml
echo '{"content": "quick note"}' | koshmana append notes -f -   # bare object → wrapped
# Anything carrying "actor" or "object" is sent as-is:
koshmana append issues -f envelope.yaml

# Declare a new collection via the catalog
koshmana declare -f collections/issues.json

# Blobs: upload a file, get its public content-addressed URL
koshmana upload photos ./logo.png
koshmana upload photos ./logo.png --type Image --name "Our logo"  # also appends a media object

# The live wire
koshmana tail issues                          # snapshot, then live activities, forever
koshmana tail issues --no-snapshot            # live only, from now

# Subscriptions
koshmana subscribe issues --webhook https://ex.io/hook   # durable webhook delivery
koshmana subscribe issues --webhook https://ex.io/hook --from-start
koshmana subscribe issues --tail              # mint a receive-only stream token
koshmana subscriptions issues
koshmana unsubscribe issues sub-abc123def456

# The raw log (truth) and tombstoning a mistake
koshmana log --from 0
koshmana invalidate issues 12 --reason "mistake"   # tombstone + compensation

# Capability grants (minting takes op `admin` on the tokens collection)
koshmana token mint --name ci --actor https://x.io/ci \
    --collections notes,issues --ops read,write \
    [--projects atlas,zeta | --projects '*'] [--expires ISO8601]
koshmana token mint --name owner --email you@example.com \
    --actor https://x.io/you --collections '*' --ops read,write,admin
koshmana token list
koshmana token revoke ci

A bare object (no actor/object key) is wrapped into an envelope (--type, default Create, attributed to --actor/KOSHMANA_ACTOR); anything already carrying actor or object passes through untouched. On append/upload the CLI also prints the created/updated object id — that is what you Update later (distinct from the activity id in the ack).

Python-client quickstart

from koshmana import Koshmana

k = Koshmana(url="https://koshmana.com", token="…")

# What exists
k.collections()
k.describe("issues")

# Append (the commit) — returns the ack {sequence, id, object, objects}
ack = k.append("notes", {
    "type": "Create",
    "actor": "https://koshmana.dev/actors/me",
    "object": {"type": "Note", "content": "hello"},
})

# Read a model; read-your-writes with min_sequence
page = k.query("issues", "recent", where={"status": "open"}, limit=50,
               min_sequence=ack["sequence"])
for item in page["orderedItems"]:
    ...

# Resolve one object by its id (O(1) lookup) — None if absent
obj = k.get("issues", "https://koshmana.com/koshmana/issues/…")

# Partial edit without dropping fields (fetch → shallow-merge → full Update)
k.update("issues", obj["id"], actor="https://koshmana.dev/actors/me",
         status="closed")

# Blobs: upload bytes, or upload + create a media object in one call
blob = k.upload("photos", png_bytes, "image/png")     # {hash, size, mediaType, url}
k.attach("photos", png_bytes, "image/png", as_type="Image", name="Logo")

# The stitch: snapshot, then the live wire, forever
for activity in k.tail("issues"):
    ...

# Declare a collection, tombstone an event, read the raw log
k.declare({"name": "notes", "schema": {"type": "object"}})
k.invalidate("issues", 12, reason="mistake")
k.log(from_seq=0, limit=200)

Raw HTTP essentials

Every call is authenticated with Authorization: Bearer <token> (except reads on public collections). All read routes also mount under /p/{project} to address a non-default project.

# Append an activity — this IS the commit
POST /collections/{coll}/events
Content-Type: application/json
{ "type": "Create", "actor": "…", "object": { … } }

# Invoke a read model (default entry "recent"); slices and bindings:
GET /collections/{coll}/recent?limit=50
GET /collections/{coll}/slices/{name}/{value}/recent
GET /collections/{coll}/{binding}/recent

# Resolve one object by id (fully percent-encode the id)
GET /collections/{coll}/objects/{object_id}
# …or dereference a minted URL id directly (public deployments):
GET /{project}/{coll}/{key}
#   Accept: text/html  → rendered via the collection's template (if any)
#   Accept: application/json (default) → AS2 JSON

# Blob upload (content-addressed; identical bytes dedup)
POST /collections/{coll}/blobs
Content-Type: image/png
<raw bytes>            →  { "hash", "size", "mediaType", "url" }

# The live wire (Server-Sent Events; `data:` lines carry each activity)
GET /collections/{coll}/live?cursor=0&watermark=-1

# The raw log (truth)
GET /admin/log?from_seq=0&limit=200

# Static-site collections (site: true) serve files by path
GET /{project}/{coll}/{path…}

Public collections (declared public: true) serve their reads and object URLs with no bearer and CORS *, so an <img>, a fetch(), or an EventSource on any origin just works. Writes are always authed.

MCP server

Shell-less hosts use the MCP server instead of the CLI — same client underneath. Install with the extra and run over stdio:

pip install "koshmana[mcp]"
koshmana-mcp        # reads KOSHMANA_URL / KOSHMANA_TOKEN / KOSHMANA_ACTOR

Tools: list_collections, describe_collection, query, append, declare, invalidate, read_log, and peek (watch the live wire briefly).

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

koshmana-0.1.0.tar.gz (16.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

koshmana-0.1.0-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file koshmana-0.1.0.tar.gz.

File metadata

  • Download URL: koshmana-0.1.0.tar.gz
  • Upload date:
  • Size: 16.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.9

File hashes

Hashes for koshmana-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f6311502b9066d2659cf4a90cd1f95a3c9b6a4cf8ee7e4f4d701b1130f05a61e
MD5 7e89ac1728a809ce02edd32d42b55091
BLAKE2b-256 920474c1414bec7234b5372c317f261747f959dbac89575b3764162ade92cdc9

See more details on using hashes here.

File details

Details for the file koshmana-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: koshmana-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.9

File hashes

Hashes for koshmana-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b72797d2c709289246b6d8d207ab9346ec1994effd7f665dc12f2f45f02ecd31
MD5 c63cfec24b13a2456e23a9dc253198e0
BLAKE2b-256 046e23eca5151919fc1672beed60c5ee2db7744ee75139dec1360d5d68b7b7ea

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.2

2 files

0.1.1

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page