Commit graph Huginn/README.md
Author SHA1 Message Date
Meta Vens
c74dd530de daemon: embeds through the endpoint pool, GPUs together and the CPU last
query-embed-on-cpu, follow-up daemon-embedder-gpu-pool: huginn-daemon takes
repeated --ollama-url (GPU hosts) and --reserve-ollama-url (CPU hosts) and
builds the same EmbedderPool as huginn-sources, through one ollama::pool
constructor. A lone --ollama-url is a pool of one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 07:56:22 +01:00
Meta Vens
7db86f7dd1 mind-heartbeat: one heartbeat routes every Persona turn on an initiative timeline; the classifier's urgency multiplies regain, an operator mention fills, a Self-run completion reaches the classifier and never fills; burn is real spend read as the heartbeat; each Persona on her own Huginn; DM rooms answered alone; the mind-wake path deleted (squash of eureka-body/mind-heartbeat d54ba01..3a4d28f; Soul s1-s4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 02:49:35 +01:00
Meta Vens
f750c78f1d README: status line with live crates, entry points and planned work; workspace has five crates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:13:58 +02:00
Meta Vens
78773a2a13 Docs: eureka-state's huginn binary is the agents' CLI
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 06:01:01 +02:00
Meta Vens
09e1b9792b Relicense the workspace AGPL-3.0-only, own the CultLib rev once, index every schema
Add the AGPL-3.0 text as LICENSE and set the workspace license to
AGPL-3.0-only (rulings license-split, leaf-relicensed-agpl); the leaf's
provenance (Epiphany ef956865, PolyForm Noncommercial, relicensed by its sole
copyright holder 2026-10-09) is recorded in its Cargo.toml and README.

One [workspace.dependencies] entry per CultLib crate now owns the revision;
the crates inherit it. index.json lists Huginn's two wire schemas too, and the
catalogue test drops its huginn. prefix exclusion: every schema file is listed.
README and AGENTS stop naming Epiphany notes as the owner of the cut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 15:15:10 +02:00
Meta Vens
c46b0ec183 Rename the pipeline leaf to eureka-pipeline and take it as a path dependency
Package and lib become eureka-pipeline / eureka_pipeline; the crate joins the
workspace; huginn-mind's git dependency on GameCult/Epiphany is replaced by
the path, and Cargo.lock is regenerated (the Epiphany source entry is gone).
Every epiphany_pipeline mention in huginn-mind, huginn-daemon and eureka-state
is renamed. The schema-publication test reads ../../schemas/cultnet. The
leaf's license-file key (../LICENSE, which Huginn has no file for) is dropped.
Type ids, the epoch and every schema_id string are untouched. Schemas README
and the pipeline section of schemas/cultnet/README.md are rewritten for the
new home; README and AGENTS no longer say the leaf is pinned by git. New test:
the catalogue lists exactly the schema files beside it.

Not yet built or tested; verification follows on Yggdrasil.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:09:16 +02:00
Meta Vens
dcb85def31 README: the daemon's full run command and where it is deployed
--qdrant-url, --ollama-url and --embedding-model are required since Cut 11a;
the example now runs. Point at the gamecult-ops runbook for the Yggdrasil
unit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:25:55 +02:00
Meta Vens
272dc09800 Add the eureka-state client core: HuginnClient::call
One call carries one HuginnMindRequest to a daemon over CultNet RUDP on the
operation connection and returns the mind's own HuginnMindResponse. Each call
is its own session and nothing survives it. A Deferred answer is fetched on
that session through cultnet-rs's fetch_content, capped at huginn-mind's
MAX_DEFERRED_BODY_BYTES, and decoded, so a caller never sees the deferral.
Refusals are answers. ClientError::Unavailable is the only error and names the
endpoint. The client opens no store and admits nothing.

Tests run a real daemon in-process on a loopback port over a temporary mind,
plus scripted servers for the failures a daemon cannot be made to produce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:41:25 +02:00
Meta Vens
5eea49f756 Cut 11b: the semantic read, joined back through the mind
Qdrant supplies candidate ids and scores and nothing else. Mind::rank drops
every hit the mind does not hold, then lets CultNet's selection decide
membership over the whole mind with its keys narrowed to the candidates, so
in_force and cited mean what they mean in query. Order is score then ordinal;
the page is cut to the selection's limit and top_k; next is never set. A
cursor with semantic, blank text and an out-of-range top_k are refused by name
before anything is embedded. Mind::query loses its semantic parameter and the
"index is not wired" refusal; the published request schema's description of
SemanticQuery follows.

The serve loop never waits on the embedder: a semantic query becomes a Search
held beside its session, the worker embeds (behind the model's query
instruction) and searches between batches, and the loop answers when the
worker has or when ServeOptions::search_timeout passes. A worker that is
Failing or Refused refuses at once, typed Unavailable naming its own error.
VectorIndex gains search; Qdrant's adapter sends no filter.

Model identity is re-read before every flush and before every search: a model
re-pulled under the same dimensions but a new digest forgets the
reconciliation instead of mixing vectors, and the next step rebuilds. An idle
worker forgets the reconciliation every Backoff::recheck (60 s), so a lost
collection is found without a write. Both go through Projector::reconcile,
still the one judge.

Also fixes a race in the worker loop found by the mutation runs: entries were
taken from the inbox under one lock and published as wanted under another, so
whoami could read a stale Current with nothing queued while the worker held
them. Taking, absorbing and publishing are now one critical section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:37:01 +02:00
Meta Vens
78f8c6ee2f Cut 11a: the index write side
huginn-mind::index owns what of a document is searchable: index_text is a
pure function per kind, Mind::index_entries builds the entries with the
writing receipt's ordinal, INDEX_TEXT_VERSION says when the rule changed.

huginn-daemon::index owns the projection. A Projector reconciles the mind
against the collection at startup (the only place a point is judged
missing: set difference on point ids, rebuild when the model name, digest,
dimensions or text version differ, refuse a collection that is not this
instance's) and one worker thread embeds and upserts in batches of 32,
retrying with a 30 s to 10 min backoff. IndexSink::committed builds entries
and leaves them in an inbox; admission never waits on the embedder or on
Qdrant. Whoami reports the worker's health as IndexStatus. The Ollama and
Qdrant adapters are the only files holding HTTP or JSON (ureq 3, no TLS).
The daemon now requires --qdrant-url, --ollama-url and --embedding-model;
NoIndex leaves the binary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 08:05:26 +02:00
Meta Vens
92ac16c5b0 Cut RS-2: delete open_items, history, and the admission window
Subtraction only, per eureka-read-side-cut.md. Deletes PipelineOpenItems,
HistoryScope, open_items, history, and the admitted_after/admitted_before
window from the read side, their wire variants and arms, the daemon arms
and tests that exercised only these, the OpenItems/History lines from the
instance-gate tests (each keeps its query and view cases), and the README
clause. serve.rs's N4 gate fixtures use whoami in place of open_items as
the long operation name; the case is kept.

Deleted the now-dead Reader::views() helper and the 'a lifetime it forced
on Reader, and stripped the History-only assertions from two tests the
map did not name (a_ref_whose_kind_and_id_disagree_is_refused_by_both_doors
and views_read_admitted_at_from_the_receipt_not_stored_at) that also called
the deleted API. Regenerated both published wire schemas.

Removes cut9 V9-V15, V22 and V22L (12 entries incl. V13L/V14L), and cut10
D19, D19L, D23, D23L, S1 and S1d (6 entries). D13 and D13L are re-anchored
on the surviving view/query arms; D13L uses a near-miss spelling rather
than a pure casing change, since PowerShell's default -eq made a casing
mutant read as "changes nothing" to the harness's own guard. V24 collapses
from a two-door Edits array to a single edit now that view is the only
door left. cut9 (27 entries) and cut10 (65 entries) both rerun clean with
M0 green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 09:51:32 +02:00
Meta Vens
a235304ae5 Describe the daemon that exists instead of the stub that does not
`huginn-daemon` serves a mind, so the README and AGENTS say what it serves,
over which envelope, in which order it starts, and where its two published
schemas live. `eureka-state` is the remaining stub. The command block gains
the daemon's own invocation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 23:00:28 +02:00
Meta Vens
49cc6e3e62 Read a mind: views, queries, open items and history
`query.rs` is the read side, over a `&Mind<S>` with no store file, no
daemon and no index. A `PipelineDocumentView` is four fields: the id,
because a `PipelineDocument` does not carry its key and a client must
never derive one; the document; the facts of its admission; and its
status.

The facts come from the commit receipts and from their `writes` alone,
so a document a later batch cited as a strong read keeps the receipt
that wrote it, and `admitted_at` is that receipt's `committed_at` -- the
`now` admission was passed -- never the store's `stored_at`. A pipeline
document the image holds and no receipt wrote is an integrity fault and
refuses; the store has one writer and the receipt is its proof.

Status is derived per call through `docs::Docs`, the same owner the
admission rules ask, so a withdrawn resolution reopens its subject for a
reader exactly when it reopens it for a rule. `closing_resolution` is
`in_force_unless`'s own body asked for the resolution rather than the
bool, so there is no second derivation to drift.

Four reads: `view` by id, `query` over the filters (root, repo, cut,
kinds, in force, faculty, an admission window), `open_items` for one
campaign's unanswered questions, standing findings, follow-ups,
unreported specs and unjudged reports, and `history` for every
resolution a subject ever had or every assignment of a repo to this
mind, withdrawn ones included with their reasons.

A query is ordered by `(admitted_at, id)`, capped at 200, and carries
`matched`, the count before the cap, so a truncation is never a short
page that reads like the whole answer. `semantic` is accepted by the
type and refused typed until Cut 11 owns the index; no substring filter
lives here to become a second answer to "the text of a document".

`cargo test -p huginn-mind --lib`: 56 passed, 0 failed, 0 warnings
(46 + the ten tests). `cargo check --workspace` clean. No dependency, no
target, no kind, no schema, no epoch; `Cargo.toml` and `Cargo.lock`
untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:22:41 +02:00
Meta Vens
fcb7fdd061 Pin the reopened subject, the retaken repo, and six blind spots
Two tests for the rules the last commit landed.
`a_withdrawn_resolution_reopens_its_subject_and_stays_readable` withdraws a
closure, admits the next one at `n2`, reads the first back with its outcome
intact, refuses a third while `n2` stands, refuses the withdrawal of the
withdrawal, and has a ruling answer the reopened question -- the derived
resolution lands at `n2`, not `n1`.
`a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer` refuses a
second assignment while the first stands and a second claiming the taken
sequence, hands the repo away, finds nothing stewarding it, hands it back and
gets `n2` with the second `handed_on`, the first still readable by key.
Entries H40-H46 carry the mutants: the two sequence rules, the recursive
in-force, `AlreadyStewarded`, the Q19 cap, and `derive`'s two sequences.

Then the six places Soul found the code right and the suite blind, each a
fixture and an entry (H47-H51): a handed-away repo is not stewarded, so
`stewardship_of`'s in-force half is pinned; a document two batch documents
cite is pinned once rather than cancelled; what a derived write cites in the
image is pinned, which is H32's surviving half; a finding may cite the
vocabulary of the target landing beside it; `Answered` coherence is checked
against a ruling in the image as against one in the batch; a branch differing
only in case is a mismatch.

H32 is re-anchored rather than left to rot. Its A4 half is unreachable now: a
derived write takes the sequence after the batch's own records, so a derived
identity cannot collide with one the batch holds. What survives is that
derived writes are validated, staged and resolved like any other, and the
transfer test's strong read is what fails when they are not.

README stops claiming the two stub crates do anything.

H1-H51 all killed, M0 green. 33 tests, 0 warnings; `cargo check --workspace`
clean; `git diff --stat 4094e68 -- .voidbot` empty.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 19:44:15 +02:00
Meta Vens
1cfa81d571 Close the epoch record, the minted leaf refusal and the nested resolution
Soul's Cut 8 pass found three rules the code only half held and one
document that promised more than the crate does.

The opener's step 3 said "exactly one epoch record at the current epoch"
and checked neither the count nor the key: a record keyed anything at all
was read as the epoch record, and a second one was never looked at, so a
current record beside a foreign one passed or refused on nothing but the
order the store returned them in. Step 3 now counts before it reads,
refuses a record under any key but the epoch, and names the defect in
`found`: the stored epoch, the offending key, or the count.

The campaign row minted `PipelineRefusal::FieldBound` for an empty
`repos`. The organ does not get to invent the leaf's refusals; an empty
`repos` is admission's own rule and is now `MindRefusal::EmptyRepos`.

The matrix admitted `Withdrawn` on a resolution, which made a subject
resolvable twice over: withdraw the resolution and the subject is open
again. A subject resolves at most once, and a resolution is not itself a
subject, so `resolution` joins `campaign`, `cut_report`, `verdict`,
`instance` and `hand_off` as not resolvable. The key grammar still spells
a resolution of a resolution; admission refuses it here. Self's default
ruling on Q17, standing until the operator rules.

`README.md` and `AGENTS.md` claimed CultNet publication and a Qdrant
connection in the present tense and called the store `.cc`. The daemon is
a stub, nothing connects to Qdrant, and the live crate writes
`mind.redb`. They say so now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 17:53:08 +02:00
Meta Vens
0bd71337fd Admit a batch through one ordered path with every rule in it
Cut 8, Huginn half, commit 3 of 4: `admission.rs`. `Mind::admit`
prepares typed documents through the leaf and calls `admit_prepared`,
the single commit path for this cut, Cut 10's sink, Cut 12's hand-off and
import, and Cut 13's tools. The steps run in order and the first failing
step is the outcome: the batch names this mind (A1), one to sixty-four
envelopes (A2), the leaf's bounds, formats and key recomputation (A3),
unique identities (A4), every instance-carrying document names this mind
(A5), an empty mind's first batch carries exactly one `instance` document
and a batch carrying one derives the epoch record (A6), every reference
resolves in image or batch by `(kind, id)` (A7), the derived writes pass
A3-A7 themselves, the per-kind rules and the resolution matrix (A8), an
exact replay answers with the stored receipt only after validation (A9),
no write collides with the image (A10), the commit (A11).

Derived writes: a ruling that answers derives the `Answered` resolution
of its question; a hand-off derives the stewardship withdrawal on its
source side and the stewardship assignment on its receiving side. "In
force" is computed at rule time from the resolutions in image and batch
and never stored; the two derivations are the only resolutions a rule
ignores when judging its own document.

Two places the leaf is thinner than the spec assumed. `FindingWithoutRange`
is unreachable: a finding envelope without `range` fails the leaf's decode
as `Document(InvalidFormat { field: "payload" })` before any organ rule,
and the test asserts that. A campaign with no repos has no refusal of its
own in the spec's list; it is refused as `Document(FieldBound)` on
`campaign.repos` with a minimum of one. `PipelineAdmissionBatch` cannot
derive `JsonSchema` because the leaf's `PipelineDocument` does not; the
outcome and refusal types do.

The epoch record is derived whenever the batch carries the `instance`
document, which only the first batch may, so a replay of the first batch
digests to the same receipt and answers `AlreadyAdmitted` instead of
colliding.

Tests: 26 (the spec's 25 plus the replay-planting test, the receipt's
deliberate second construction site). `cargo check -p huginn-mind --lib
--tests` and `cargo test -p huginn-mind --lib` pass with zero warnings;
`cargo check --workspace` passes. README says what the crate does now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 17:13:44 +02:00
Meta Vens
946758f666 Open a mind fail-closed over an owned redb store
Cut 8, Huginn half, commit 1 of 4: the store port, the opener and the
identity rules. `huginn-mind` gains its dependencies (`cultcache-rs` at
Epiphany's pin `a0813c6`, `epiphany-pipeline` at `a65c6420`, the Epiphany
half of this cut), `store.rs` with the one narrow `MindStore` trait that
injects compare-and-swap, `mind.rs` with `Mind::open` and `open_with`, and
`refusal.rs` with the organ's refusal vocabulary.

The opener refuses in order and attaches nothing until every gate passes:
a foreign type, a foreign epoch, a missing identity, an identity naming
another instance. The path under the state root is derived from the slug;
the `instance` document is the authority, so a store copied into another
instance's directory is refused. The owned store's exclusive lock is the
single-writer mechanism: a second `Mind::open` of the same path is
`MindAlreadyOwned`.

The receipt type and the two provenance shapes (`Faculty`,
`PipelineProvenance`) land here rather than in the later commits because
the opener registers the receipt's type id, and their only consumer is the
receipt; the commit primitive itself is the next commit. `MindRefusal`
carries a serde remote definition of the leaf's `PipelineRefusal`, which
derives neither `Serialize` nor `JsonSchema` at the pinned rev; it is
compiled against the leaf's type so a leaf change breaks the build rather
than drifting.

`Cargo.lock` is regenerated and gains 90 packages. The map predicted a
CRLF-to-LF rewrite of the whole file; the file was already LF in the index
and stays LF, so the diff is additions only.

README and AGENTS now say `huginn-mind` is live and the other two crates
are stubs.

Builds: `cargo check -p huginn-mind --lib --tests` and `cargo test -p
huginn-mind --lib` (4 tests) pass. This commit carries dead-code warnings
on the store and cache accessors and the refusing test store; commits 2 and
3 consume them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 17:04:23 +02:00
Meta Vens
e20c786c96 Describe Huginn as the memory organ
README and AGENTS now state what Huginn is: the single writer of each
instance's mind as typed CultCache state, published over CultNet, depending
on Qdrant directly and refusing loudly without it. Generic .cc inspection is
CultCache Studio's. The docs name the Rust workspace, the F: drive body, and
the cut map that owns what each crate does next.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 15:12:18 +02:00
Meta Vens
afee1a262f Document Huginn repo swarm wiring 2026-06-21 15:51:46 +01:00
Meta Vens
0d58398b4b Reduce Huginn to Eve DSL projection 2026-06-05 12:42:30 +01:00
Meta Vens
49970186dd Make Huginn consume CultLib CultCache 2026-06-05 12:23:59 +01:00
Meta Vens
a079386a3e Make Huginn emit Eve DSL only 2026-06-01 22:15:39 +01:00
Meta Vens
d905639ecf Point inspector at Norn viewer 2026-05-25 18:19:03 +01:00
Meta Vens
e3f0d8ffaf Drive Huginn stardust from packed art channels 2026-05-19 14:08:05 +01:00
Meta Vens
8b36467c09 Make Huginn payload cloud and stardust viewport native 2026-05-19 13:35:39 +01:00
Meta Vens
1feea63f63 Bump release version to 0.12.0 2026-05-19 10:47:20 +01:00
Meta Vens
172548b704 Calm Huginn particles with quadtree stardust 2026-05-18 22:47:34 +01:00
Meta Vens
32ccf43a0f Rebuild Huginn graph inspector 2026-05-18 11:01:16 +01:00
Meta Vens
e5c4c9dd50 Embed EpiphanyGraph in Hugin 2026-05-18 03:56:43 +01:00
Meta Vens
8631f0ab62 Brand inspector as Hugin 2026-05-18 03:41:06 +01:00
Meta Vens
b460612680 Add CultCache inspector app 2026-05-16 11:06:33 +01:00
Meta Vens
434c0c006e Align single-file store with CultCache v1 snapshots 2026-05-16 08:53:07 +01:00
Meta Vens
ed3f2b8dd7 Add raw envelope fast path to CultCacheTS 2026-05-06 11:23:12 +01:00
Meta Vens
b7cc33a846 Accept generated parse-style schemas in CultCacheTS 2026-05-06 06:33:13 +01:00
Meta Vens
be0a96db7b Expand CultCacheTS toward full CultCache ergonomics 2026-05-06 04:41:11 +01:00
Meta Vens
0c430c3c0e Initial CultCacheTS port 2026-05-06 03:11:02 +01:00