# `Bee`
[🔗](https://github.com/fosferon/bee/blob/v0.3.0/lib/bee.ex#L1)

A dependency-aware work-coordination engine over SQLite.

Model units of work as issues, link them with a typed dependency DAG, and query the
result through a composable spec or a named *intent*. Bee computes ready sets,
critical paths, and effort rollups; records every mutation to an append-only event
log; and accepts opaque measurements (cost, tokens, duration) to calibrate its own
outputs.

## Setup

Add `Bee.Supervisor` to your supervision tree:

    children = [
      {Bee.Supervisor, db_path: "priv/bee.db", prefix: "bee"}
    ]

## A first workflow

    {:ok, a} = Bee.create("Implement auth", priority: 2)
    {:ok, b} = Bee.create("Add billing")
    :ok = Bee.block(b.id, a.id, type: :blocks)
    {:ok, ready} = Bee.ready()                  # => [%{id: 1, ...}]  (billing is gated)

    {:ok, %{issues: top, withheld: withheld}} =
      Bee.query(status: "open", limit: 5)        # `withheld` reports what was truncated

## Two surfaces

This module is the in-process facade. Bee also publishes a versioned GenServer
message protocol (`{:create, title, opts}`, `{:ready, opts}`, ...) for node-crossing
consumers — a change safe for one surface is proven safe for the other.

The full guide — dependency vocabulary, the allocation tree, measurements ×
dimensions, the event log, and configuration — lives in the README, which is the
HexDocs landing page.

# `agent_load`

# `ancestors`

Returns `{:ok, [%{id, title, status, issue_type, project_id}]}`: the parent chain
of `id`, root first, excluding `id` itself (`[]` for a root). `{:error,
:not_found}` for an unknown id. The walk is bounded, so it terminates even over a
corrupted parent cycle.

# `ask`

Resolves an intent — an atom for a built-in (`:what_next`) or a binary name
registered via `register_intent/3` — into a query spec and runs it.

Returns the same shape as `query/2`. Intents are pre-composed queries: one engine,
no drift between a shortcut and the spec it stands for.

# `assign`

# `associate_lane_issue`

Atomically links an existing Bee issue to a Work Lane as `"root"` or
`"member"`. `attrs` has exactly `:command_id`, `:lane_id`, `:issue_id`
(a full Bee issue ID), `:role`, and `:project_id` (the expected Bee
project, or `nil`). A matching command replays its durable receipt.
Conflicts and missing issues return tagged errors without changing a link.
This command never changes `issues.project_id`.

# `backfill_projects`

Atomically backfill positively qualified issue targets and their audit rows.

# `block`

Adds a dependency: `id` is gated by `blocker_id`. `type:` selects the dependency
type (default `:blocks`; see the README for the full vocabulary). Returns `:ok` or
`{:error, :cycle}` if the edge would create a cycle. Only gating types feed
`ready/0` and rollups.

# `block`

# `bottlenecks`

# `candidates`

# `classify_lane_write`

Bee-owned diagnostic target classification; not a mutation permit.

# `comment`

# `count`

Counts issues matching `opts`: the `list/2` filters plus the query spec's filter
fields (`:under`, `:include_root`, `:depth`, `:labels_any`, `:issue_types`,
`:priority_min`, `:priority_max`, `:has_children`, `:blocked`). An unknown
`:under` returns `{:error, {:not_found, id}}`.

Runs on a pooled reader in the caller's process, not through the writer.

# `create`

Creates an issue. Returns `{:ok, issue}`.

Supported options: `:description`, `:priority` (integer), `:issue_type` (or `:type`,
default `"task"`), `:labels` / `:label`, `:parent` (an issue id), `:project_id`,
`:actor` (the creator), and `:metadata` (a map; reserved prefixes are `bee:` and `_`).

# `critical_path`

Returns `{:ok, [ids]}` — the longest dependency path through the gating DAG,
computed with a memoized topsort rather than exponential recursion. Pass `:root`
for the blocker-to-goal chain ending at one issue, or scope the global path with
`:project_id` and/or `:status`. `:types` selects dependency types and `:depth`
bounds rooted traversal (maximum 100).

# `critical_path`

# `critical_path`

# `get`

Fetches a single issue by id. Returns `{:ok, issue}` or `{:error, :not_found}`.

By default relations are not loaded (`comments: :not_loaded`). Pass `include:`
to load them:

    {:ok, issue} = Bee.get(1, include: [:comments])

# `get`

# `get`

# `get_comments`

# `import_jsonl`

# `join_project`

# `lane_write_fence_status`

Owner cutover status; diagnostic only, never an admission permit.

# `list`

# `list_agents`

# `list_intents`

# `list_measures`

# `list_projects`

# `lock`

Acquires a lock on an issue. Options: `:locked_by` (holder id), `:ttl` (minutes,
default 30), `:force` (take the lock from its current holder).

Returns `{:ok, lock}` or `{:error, :already_locked | :not_found}`. Expired locks
are released by a background sweeper.

# `measure`

Records an opaque measurement against an issue. `attrs` carries `:measure`,
`:value`, optional `:source`, and `:dims` — a map whose keys must match
`[a-z][a-z0-9_]*` and which **must** include `"kind"` (`"estimate"` or `"actual"`).

# `mutate_lane_issue`

Internal admitted lane issue mutation; caller admission is rechecked inside the owner transaction.

# `query`

Runs a composable query. Returns
`{:ok, %{issues: [...], withheld: map, refine: keyword}}`.

`withheld` reports omissions (a truncated `limit`, omitted relations) and `refine`
suggests how to ask for what was held back. Filter by plain-text `:text`, `:status`,
one `:project_id` or any of `:project_ids`, `:ready`, `:blocked`, `:assigned_to`,
`:labels` (all of) or `:labels_any` (any of), `:issue_types`, `:priority_min` /
`:priority_max`, and `:has_children`; sort with `:order_by`; page with `:limit` and
either `:offset` or an `:after` cursor; load relations with `:include`; and shape
each result with `:detail` (`:minimal | :compact | :standard | :full`).

The result also carries `total` (the match count without `limit`/`after`) and
`next`, a keyset cursor for the following page (or nil). Pass it back as `:after`
with the same spec: unlike an offset it stays stable while issues are created or
closed between pages.

## Parent trees

  * `:under` — only strict descendants of that issue over parent edges
    (`include_root: true` adds the issue itself at depth 0). An unknown id returns
    `{:error, {:not_found, id}}`.
  * `:depth` (0..10) — the deepest level returned; each issue then carries `depth`.
    With `:under`, children are depth 1. Without it, depth counts from the nearest
    ancestor that passes the `:status` filter, so an open issue under a closed
    parent is depth 0 in an open-only view.
  * `fold: true` (requires `:depth`) — each issue carries `rollup`, counts over its
    whole real subtree whatever the other filters say.
  * `path: true` — each issue carries `path`, its ancestors from the top down to its
    parent, closed ones included.
  * `keep_ancestors: true` — the ancestors of each match come back too, marked
    `context: true` and listed first; they do not count toward `limit` or `total`.

Runs on a pooled reader in the caller's process, not through the writer.

# `ready`

Returns `{:ok, issues}` — every open issue with no *gating* dependency still
outstanding. Honours `:blocks`, `:waits_for`, and `:conditional_blocks`.

# `reconcile_lane_issue`

Reads a Bee-owned receipt and its *current* issue/link state on the writer.
`:matching` proves the recorded link and project still match; `:stale`
means they have drifted. `:not_found` is a snapshot, not proof that an
earlier queued or uncertain command can never commit.

# `reconcile_lane_mutation`

Authenticated owner receipt/current-state read; missing receipt is not an abandonment proof.

# `register_agent`

# `register_intent`

Stores a named query spec (persisted in the database). Resolve it later with
`ask("name", ...)`.

# `register_measure`

Registers a numeric measure (e.g. `"effort"`, `"tokens"`) with a unit and an
optional value `:domain` (`:any` or `:non_negative`). Required before `measure/3`.

# `register_measure`

# `register_measure`

# `register_project`

# `remove_intent`

# `rollup`

Aggregates effort (`measure: "effort"`) over a scope rooted at `id`.

Options: `:scope` (`:tree` | `:closure` | `:critical_path`, default `:tree`),
`:kind` (`:estimate` | `:actual`, default `:actual`), `:meaning` (`:spent` |
`:to_complete`, default `:spent`). If any node lacks a measurement, `total` is
`nil`, a `partial_total` is given, and `refine` lists the missing ids — bee never
silently invents a sum.

# `traverse`

Walks the dependency graph from `id`. `direction: :blockers` (default) follows
gating edges toward what gates `id`; `:dependents` follows them toward what `id`
gates. Returns `{:ok, [ids]}`.

# `tree_page`

# `unblock`

# `unblock`

# `unlock`

# `update`

Updates an issue with a map of attributes. Returns `:ok` or
`{:error, :not_found | :self_parent | :parent_cycle}`.

A `:measure` key may be folded into the update to record a measurement atomically
with the status change that earned it.

# `upsert_project_registry`

Canonical registry upsert with original-row comparison inside the owner transaction.

# `who_blocks_whom`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
