Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Previously

Previously, on Project …

A tool that gathers courses of events, commitments and open points from many channels, orders them and makes them provable — so that the question "how do things stand here?" is answerable without looking into six mailboxes.

The name is the main view: the header and the chronicle of a project, every line with its source attribution.

State

Stages 1a, 1b and 1c are built and run: the append-only log with its hash chain, the projections derived from it, and blobs and erasure. A release publishes a package on PyPI and an image on ghcr.io. The first connector takes the mail of an IMAP folder in, and a gate lets a language model read it only as far as a policy in the log allows; an MCP server lets Claude Code or Mistral Vibe read it under the same policy. Obligations and decisions are recorded with the mails they rest on, and a client proposes them for a person to approve. Not a product surface — a command line thin enough to get at the log by hand, so that each stage is runnable and not merely described.

What it does:

  • an append-only event log in PostgreSQL, every event hash-linked to its predecessor (SHA-256 over canonicalised JSON after RFC 8785)
  • appending with idempotency over (source, external_id), and without any prior lock: concurrent writers serialise on unique indexes, and the loser re-reads the tip and repeats
  • units — plain text split at blank lines, numbered, each with a salted digest of its own (hash format 2), covered by the hash
  • checking (verify): for every existing row the payload, the units, the source attribution, the linkage to the predecessor, and a count reconciliation that proves no row lay outside the check
  • projections (project) that are derivable from the log and disposable: projection_state records how far each one has got, and a raised derivation version empties its table and builds it again from the log
  • the chronicle (chronicle) — one line per unit with its source attribution, in the order in which things happened rather than the order in which they were recorded
  • the per-source statistics (stats): events, units, and the earliest and latest occurred_at per source
  • the external anchor (anchor, verify --anchors): anchor prints the tip of an intact chain as one line <id> <hash>, to be kept where the database's writer cannot write; verify --anchors checks the log against such lines, so that up to the newest anchor nothing can go missing or be rewritten unseen
  • blobs (append --attach, blob get): a file attached to an event is sealed in the age format before it leaves the process, stored in an S3 bucket under the SHA-256 of its content, and named in the payload; blob get fetches it and writes it out only if it matches its address. Losing the identity that opens the blobs loses every blob sealed to it, for good: How to keep the blob key safe says how to back it up and rehearse the backup
  • erasure (redact): an event, some of its units, or a blob, erased as an event of its own in the same chain, so that a tombstone without an order is a finding; every hash stays, the salt goes, the projections follow, and a blob leaves the store once no reference to it is left. An event written before stage 1c, in hash format 1, has no salt, so short erased content stays guessable from its digests; see About erasure
  • checking the blobs (verify --blobs): every blob that has to lie in the store is read, opened and held against its address, and every erased one has to be gone
  • taking in mail (ingest imap): the mail of one or more folders of an IMAP mailbox, each folder with a watermark of its own, read over TLS without changing the folder, each mail an event with its subject and paragraphs as units, its raw bytes and every attachment as blobs, and a mail forwarded as an attachment an event of its own. A mail is recognized by an identity of its content, so a second copy, the same mail in a second folder or a folder read again writes nothing, and a changed mail under a known Message-ID becomes a variant instead of being lost; see About connectors and How to take in the mail of a folder
  • the gate and the processing policy (policy, gate): circles of people, rules for them and what each provider promises, all as events in the same chain; for a mail, gate explain shows which model at which provider in which region may read it, and gate try makes the call. Without a rule only a local model is allowed, and the fallback shows. Every attempt, a denied one included, becomes a model_call event that holds no content, and an erasure of the mail takes the answer with it; see About the processing policy, About trust boundaries and How to set a policy and try a call
  • MCP access (client, mcp, serve, access): Claude Code, Mistral Vibe or a local harness reads the chronicle of a circle, single mails, and the obligations and decisions through ten tools, each client named, declared as a processor and, over HTTP, holding a token of its own, so that the policy decides for every event whether this client may see it, and shows a placeholder with the reason where it may not. Every call becomes an mcp_access event that holds no content, and access lists what each client saw and what was withheld; see About the client interface and How to connect Claude Code and Mistral Vibe
  • assertions (assert, approve, reject, obligations, obligation, decisions, decision): who owes whom what and by when, and what was decided, each resting on named mails and their units, written in complete versions with an author and a responsibility of their own. A client proposes through write_assertion, a proposal stays one until a person approves it, and a direct statement always outranks a proposal. An erasure of a mail takes every assertion on it along; see About assertions and How to record what's owed and decided
  • the twenty-five commands migrate, append, ingest, redact, log, verify, anchor, show, blob, project, chronicle, stats, policy, gate, client, access, assert, approve, reject, obligations, obligation, decisions, decision, mcp and serve
  • the schema as Alembic migrations inside the package, applied by previously migrate

What it does not do: no header, the view of a project that rests on its assertions; no layer behind the gate that proposes assertions by itself; no assignment of events to projects, so the chronicle is the chronicle of the whole log and not of one project; no job queue — the projection worker is a command, run when somebody runs it; one connector, for an IMAP folder, and none for anything else yet, such as a shared folder or an issue tracker; no people or organizations as entities, so an actor is the own side, a circle, an address or a plain label; no action that writes into a foreign system, and one task only for the gate, an overview of a mail that is a probe and no result anything relies on; no search, no user administration, and no network interface but the MCP server.

And one limit that is not a gap but the nature of the thing: a hash chain by itself bears witness that what stands in the log is unchanged — not that it is complete. Deleting the tip, appending a self-computed event or rewriting the whole chain leaves a result that is consistent in itself. An external anchor, kept where the database's writer cannot write, adds completeness up to the newest anchor: a deleted or rewritten event below it shows. What it does not add is the interval since: a tip deleted above the newest anchor shows nowhere, and a forged appended event shows only against an anchor taken at a moment of rest, when nothing legitimate should have been written since. About the hash chain states which forgeries are covered and which are not.

An erasure has a limit of the same kind: it takes content out of the log and out of the bucket, not out of the backups taken before it, and a restore to an earlier point brings it back. The address of a blob and the source key stay as well, and an erasure of units leaves their wording in a payload that holds it too, and says so when a string of the payload contains a unit's wording. For a mail, it reaches neither the folder the mail came from, nor the backups of the mailbox, nor the replies that quote it, and a promise of erasure never covers the source the mail came from; About erasure says what an erasure does not achieve and why.

Install

Each release is a package on PyPI and a container image on ghcr.io, for linux/amd64 and linux/arm64. Until 1.0.0 every release is an alpha, so ask pip for a pre-release, or name the version:

pip install --pre previously

The image runs previously as its entry point, and an alpha has one tag only, its exact version — no latest:

docker run --rm ghcr.io/jensens/previously:0.1.0a1

Either way, Previously reads its settings from the environment, and previously migrate creates or upgrades the schema before any other command runs against a database. How to run Previously from its image shows the image at work, and How to cut a release how a release comes about.

Documentation

The full documentation — tutorials, how-to guides, reference and explanation — lives under docs/. Build it locally with make -C docs html, then open docs/_build/html/index.html. Start with Record your first event: a session typed out against a real PostgreSQL 18, from a fresh checkout to a passing test suite.

The twelve specifications below are frozen design records, in German and dated: they hold how and why a decision was taken, and the documentation under docs/ carries the reasoning that is maintained with the code. Where the two disagree, the documentation wins. A new stage starts with a new German specification, which freezes once its explanation pages stand — stage 1b is the first one that went that way from the start.

Document Content
Design Frozen design record, 2026-10-03: goal, guiding principles, core model, attribution, projections, release model, acceptance conditions
Architecture Frozen design record, 2026-10-03: modules and boundaries, schema, connector contract, process model, MCP (superseded by the MCP interface below), tooling
Stage 1a Frozen design record, 2026-10-03: detailed specification of the append-only log with its hash chain
Stage 1b Frozen design record, 2026-10-04: detailed specification of the projections — the two derived tables, the worker, and the three commands; its reasoning is maintained in About derived views and About the module boundaries
External anchor Frozen design record, 2026-10-04: detailed specification of the external anchor — the anchor line, anchor, and verify --anchors; its reasoning is maintained in About the hash chain, the routines in How to check the chain in operation and How to check how much of the chain a restore brought back
Stage 1c Frozen design record, 2026-10-05: detailed specification of blobs and erasure — hash format 2 with its salt, erasure as an event, blobs sealed in age on S3, and the commands redact, blob get and verify --blobs; its reasoning is maintained in About erasure, About blobs and About the hash chain, its routines in the guides under How-to guides, and its open points in the map
Delivery Frozen design record, 2026-10-05: detailed specification of the way out — the migrations in the package and previously migrate, the release workflow to PyPI and ghcr.io, the image and its smoke test, and the handoff to the maintainer's Kubernetes environment; its reasoning is maintained in About delivery, its routines in How to cut a release and How to run Previously from its image, and its open points in the map
Pilot, unit 1 Frozen design record, 2026-10-06: detailed specification of taking mail in from an IMAP folder — the identity of an artifact and the channel identities in the contract, a mail as an event, the connector contract with its watermark, the run, and previously ingest imap; its reasoning is maintained in About connectors and About erasure, the mapping in Mail mapping, its routine in How to take in the mail of a folder, and its open points in the map
Pilot, unit 3 Frozen design record, 2026-10-09: detailed specification of the gate and the processing policy — circles, rules and the promises of providers as events, the decision, three adapters, and the audit of every model call; its reasoning is maintained in About the processing policy and About trust boundaries, its routine in How to set a policy and try a call, and its open points in the map
MCP interface Frozen design record, 2026-10-11: the concept of the MCP interface as a whole — tools, resources, prompts, access, the processing check of a client, the access log, the form of a result, versions and operation; it replaces §8 of the architecture, and its reasoning is maintained in About the client interface
Pilot, unit 4 Frozen design record, 2026-10-11: detailed specification of MCP read access — clients as principals, the extended processing chain, previously mcp and previously serve, five tools, and mcp_access; its reasoning is maintained in About the client interface, the facts in Server tools, resources and prompts, its routine in How to connect Claude Code and Mistral Vibe, and its open points in the map
Pilot, unit 5 Frozen design record, 2026-10-12: detailed specification of assertions — obligations and decisions in complete versions, references to actors, precedence by responsibility, proposals over MCP with approval and rejection, the cascade of an erasure, and the policy over the sources; its reasoning is maintained in About assertions, the facts in Assertions, its routine in How to record what's owed and decided, and its open points in the map
Execution records Frozen working records, one directory per executed plan: the ledger of every decision taken while building it, and the target of the ruling … citations in the code
CLAUDE.md The working agreements: language, attribution, dependencies, the six gates
DEPENDENCIES.md Every dependency with its purpose, the rejected alternative and the date it was last checked
NOTIZEN.md The conversation log of how it came about, the discarded routes included

Licence

AGPL-3.0-or-later.

Affero deliberately: Previously is a server application, and the ordinary GPL does not bite when somebody runs a modified version as a service without handing out code.

Metadata

Release files for previously 0.1.0a5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for previously 0.1.0a5
File Size Uploaded Provenance
previously-0.1.0a5.tar.gz 2.9 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for previously 0.1.0a5
File Interpreter ABI Platform
previously-0.1.0a5-py3-none-any.whl Python 3 none any Details

Total release size: 3.3 MB

Release files / previously-0.1.0a5.tar.gz

Download URL previously-0.1.0a5.tar.gz
Size 2.9 MB
Tags Source
SHA-256 checksum
How to use checksums
05001555d7c008437c6e35bbe1ea6f92cbefb9b3c161e8e567ff6e4e9f7f6038
BLAKE2b-256 checksum
How to use checksums
7187040905d6dbe9d54e157030d4b2d781bf01f2b6cf0b82e345bc5cf9d02127
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / previously-0.1.0a5-py3-none-any.whl

Download URL previously-0.1.0a5-py3-none-any.whl
Size 306.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9a1a9ccf2d790b7c47933ff035c2b0176632a8a5647a606ca8b710a28933c931
BLAKE2b-256 checksum
How to use checksums
d7a46e83d567d0e8bafd7c708cb0737ff65aaffcdb1716245c64e5cff58061fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Security for previously 0.1.0a5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for previously-0.1.0a5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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