Assembles a work packet: context delivered, not discovered.
Given the contexts a task touches, the packet gathers (a) the map slice
for those contexts, (b) their intent cards verbatim, (c) draft designs
anchored to them — inlined loudly, they are live intent not yet distilled
into cards — and accepted designs as pointers, (d) per-directory agent
guidance (AGENTS.md/CLAUDE.md next to the context's source) verbatim,
(e) plausibly related routes and jobs, and (f) pointers to runtime
verification when Tidewave is present. The rule is link, don't restate:
the packet carries the source records and points at everything else; it
never paraphrases code into a second truth.
Summary
Functions
Builds a work packet for the named contexts (["Deals", "Billing"]).
Builds a packet for the contexts touched by a set of changed files —
typically a branch diff (mix cohere.packet --diff).
Resolves changed files to the context groups that own them, using a
%{source_path => [module]} index (see Cohere.Project.source_index/1).
Reverse index: every module owned by a context group → the group name.
Guidance files (AGENTS.md, CLAUDE.md) living in the directories a
group's modules compile from — source-index-derived, not path convention.
Functions
@spec build(Cohere.Project.t(), [String.t()]) :: {:ok, String.t()} | {:error, term()}
Builds a work packet for the named contexts (["Deals", "Billing"]).
Returns {:ok, markdown} or {:error, {:unknown_contexts, names}}.
@spec build_for_files(Cohere.Project.t(), [String.t()]) :: {:ok, String.t(), map()} | {:error, {:no_contexts, [String.t()]}}
Builds a packet for the contexts touched by a set of changed files —
typically a branch diff (mix cohere.packet --diff).
Returns {:ok, markdown, report} where report is
%{contexts: [name], unmapped: [file]}, or
{:error, {:no_contexts, unmapped}} when nothing mapped. The packet
carries a scope note listing the contexts covered and the changed files
that did not map to any — never a silent slice.
@spec contexts_for_files(Cohere.Map.t(), %{required(String.t()) => [module()]}, [ String.t() ]) :: map()
Resolves changed files to the context groups that own them, using a
%{source_path => [module]} index (see Cohere.Project.source_index/1).
Returns %{contexts: [name], unmapped: [file]}, contexts deduped in
first-seen order. A file whose modules belong to no context group —
web modules, config, migrations, non-source — lands in unmapped.
@spec group_index(Cohere.Map.t()) :: %{required(module()) => String.t()}
Reverse index: every module owned by a context group → the group name.
Guidance files (AGENTS.md, CLAUDE.md) living in the directories a
group's modules compile from — source-index-derived, not path convention.
Root-level guidance is excluded: every harness loads it already, so the
packet keeps it as a pointer (DEC-PAC-004 in
cohere/design/packet-sources.md).