Skip to main content
A program that watches or drives a campaign, such as a dashboard, a bot or your own controller, reads piloop with three commands. Each prints one JSON document on stdout. Messages go to stderr.

Read without a gap

  1. Read a snapshot. Its cursor is the id of the newest event that the snapshot includes: the snapshot and the cursor come from one read transaction.
  2. Read the events after that cursor, then after the next of each read. While more is true, read again at once. When it is false, add --follow to wait for the next event.
  3. Save the cursor after you have handled a batch. After a crash or a disconnect, read again from the saved cursor.
Delivery is at least once: when you resume from a saved cursor, an event that you handled before you saved it comes again. Skip an event whose id you have handled. Each program keeps its own cursor. piloop keeps no state for a reader. --project and --kind filter the events. The next cursor still passes every event that the read examined, so a read that matches nothing moves on, and a filtered reader never reads the same range twice. --project also keeps the events whose project is unknown (see subject.project below), because they may be of that project: a project reader misses none of its events, and may get a few of other projects.

The documents

Every document has protocol, the version of the documents and of the event envelope: 1. Within a version, piloop may add fields. Ignore the fields that you do not know. A change that removes or changes a field is a new version. A read of events:
piloop status --json has cursor, daemon (pid, null when the daemon is not running) and projects. Each project has its id, name, path, status and stopped_reason, paused (launches, all or null) and paused_reason, the current evaluator, the head (its candidate, and for each track the primary metric, its value and its delta against the baseline; null when there is no keep yet), the kept and candidates counts, the number of ideas in each status, the runnable ideas, the open runs, the live agents, the unacknowledged inbox items and the tokens spent. It covers the projects that piloop status would show. piloop inbox --json has cursor, items and seeds, with the filters of piloop inbox.

The event envelope

Every event has the same fields, whatever its kind. The envelope shows each stored event as it is. It rewrites no row and invents no field. subject.project is looked up when the event is read, so it is null when the row is gone (a deleted idea, its older events and its idea.deleted included) or has no project (a reply to a reply). piloop checks the types of an event when it is written, through any piloop command, piloop sql included. A payload can still be text that is not strict JSON, such as NaN or 1e400, and a row that an older piloop let through can have a time that is not a time. Such a value comes as null with its stored text under invalid, and the events after it read as usual. The documents are always strict JSON. An event kind that this version of piloop does not know, such as a plugin’s, comes in the same envelope with its payload as opaque JSON. A reader that does not need it skips it and moves its cursor on. The subjects are rows of the tables in the data model. The events table has the stored rows: the database schema.

Errors

--json reports an error that a program can act on as a document with error.code and error.message, and exits with status 1. The message goes to stderr too. Other failures, such as an unknown project or a bad option, print a message on stderr, print nothing on stdout, and exit with a status other than 0. cursor_ahead only catches a cursor that is ahead of this feed. A cursor of another home that is behind this feed’s end reads as a valid one: keep one cursor per piloop home.