Skip to content

v0.2.6

Choose a tag to compare

@github-actions github-actions released this 31 Jul 00:43
· 246 commits to main since this release

Added

  • Python client sagewiki (clients/python/, P4-3). Typed sync
    (SageWiki) and async (AsyncSageWiki) clients over the /v1 REST API —
    one shared request-building implementation, httpx as the only
    dependency, stdlib dataclass models, py.typed shipped. One method per
    route; the full error-code vocabulary maps to exception classes (branch
    on code, never message); compile/lint return a Job whose
    wait(timeout) requires an explicit timeout (raises JobTimeout,
    JobFailed; returns on cancelled); Conflict.active_job_id exposes
    the 409 details; idempotency keys forwarded verbatim and required before
    any write is retried. Contract-tested against a live server in CI
    (scripts/p4-fixture-server.sh — a keyless fixture seeded through the
    write API). Pre-1.0 — pin a version.
  • TypeScript client sagewiki (clients/typescript/, P4-4). Typed,
    zero-runtime-dependency client over /v1 using global fetch — runs on
    Node ≥18, Deno, Bun, and edge runtimes (no Node built-ins in the main
    entry, statically asserted). Dual ESM + CJS output with types.
    Compile-submit bodies are discriminated unions: mixing topic with
    compile flags is a compile-time error. Same error taxonomy as the Python
    client (instanceof and switch (e.code) both work), AbortSignal on
    every method including job waits, waitUntilDone({ timeoutMs }) with a
    required timeout. Contract-tested against a live server in CI.
  • Framework examples (examples/, P4-6). Two CI-exercised, keyless
    examples: examples/langgraph/ — retrieval + capture nodes showing the
    uncompiled_sources > 0 → topic-compile-and-wait pattern (stubbed LLM);
    examples/vercel-ai-sdk/search, graphQuery, provenance as AI
    SDK tools, with the edge-deployability note. Both run headlessly in CI
    against the fixture server and assert a non-empty result. Exactly two, by
    design.
  • Publish workflows. publish-python.yml (PyPI Trusted Publisher) and
    publish-typescript.yml (npm with provenance), manual-dispatch or
    py-v*/ts-v* tag triggered, version-match checked, with a post-publish
    pin-resolution verification step. Publishing itself remains maintainer-run.

Fixed

  • Jobs submitted via /v1/jobs/* were cancelled the instant their 202
    was sent.
    The job goroutine derived its context from the HTTP request,
    which net/http cancels when the handler returns — so every job died as
    soon as submission completed (invisible to httptest, which never
    reproduces request lifecycle cancellation; caught by the Python client's
    live contract test). Job contexts now derive from context.Background()
    with the existing 2-hour cap, pinned by a regression test that drives a
    real server and client.

Added

  • Async job API for compile and lint (/v1/jobs/*, P4-2). Long-running
    operations are now job submissions over REST: POST /v1/jobs/compile
    (full mode via compile flags, or topic mode via {topic, max_sources?})
    and POST /v1/jobs/lint return 202 Accepted with a job_id; poll
    GET /v1/jobs/{id} through pending → running → done | failed | cancelled, list recent jobs via GET /v1/jobs (bounded to 100, FIFO
    eviction), cancel via DELETE /v1/jobs/{id} (best-effort; the compile
    checkpoint stays resumable). Submitting while a compile is active returns
    409 conflict with the active job's ID; Idempotency-Key on submit
    replays the same job_id without re-dispatching (per-kind scoped,
    X-Idempotent-Replay: true); compile jobs mirror the shared progress hub
    into the job's progress field. Jobs dispatch to the same compile/lint
    functions the MCP tools call — no parallel job system; records are
    in-memory (same restart semantics as the idempotency store). MCP tool
    behaviour is unchanged.
  • Agent skills: sage-wiki reference + sage-wiki-integrate pipeline
    (P4-5).
    Two installable skills generated from the live MCP tool
    registry (go run ./tools/skillgen/): the reference skill documents all
    18 MCP tools with REST equivalents, the fixed error-code vocabulary,
    opt-in flags with their true defaults, tiers 0/1/3, and async compile
    semantics; the pipeline skill wires sage-wiki into an existing repo
    (detect language → client or MCP config → smoke test). A CI drift check
    regenerates and git diff --exit-codes the skills/ tree, so a tool
    change cannot ship with stale skills. Install:
    npx skills add https://github.com/xoai/sage-wiki --skill sage-wiki.

Fixed

  • Batch API truncation no longer silently drops sources (#124). Also
    fixes a pre-existing Gemini batch bug: retrieve failed SSRF validation on
    any port-bearing base URL (host comparison dropped the port). A
    truncated 200-OK results body previously produced a partial result set
    that was processed as complete (malformed JSONL lines were skipped
    silently). Retrieving batch results now retries truncation-class errors
    with backoff on all providers, malformed lines error out instead of
    skipping, and the resume path hard-fails with the missing source names
    before any processing when a batch returns fewer results than expected —
    the checkpoint is kept for re-poll instead of consumed.

Added

  • Evidence gates for low-evidence concepts (#128). Bare acronyms scraped
    from legends and passing references no longer become standalone
    boilerplate concept articles: extraction dedup now merges concepts on
    normalized alias overlap (an extracted "rap" folds into
    "remedial-action-plan" when the alias is known, in-batch or from prior
    compiles via new manifest-stored aliases), and a new
    compiler.min_concept_sources gate (default 1; 0 disables) fully
    suppresses concepts with no declared sources — no article, no LLM call,
    no manifest entry, on all three compile paths. The extraction prompt also
    tells the model not to emit unresolvable acronyms as standalone concepts.

Fixed

  • init no longer destroys user files (#127). Re-running sage-wiki init
    preserves .gitignore (appends .sage/ instead of clobbering) and
    .manifest.json (skips when present — previously every re-init wiped
    compile history and orphaned the vault). New --force flag rewrites both
    intentionally (config.yaml stays preserved unconditionally). Also:
    sage-wiki init <dir> now honors the positional directory argument —
    previously it was silently ignored and the current directory was
    initialized instead, which could scatter (and wipe) the wrong directory.
    More than one positional argument is now an explicit error.

Added

  • Backend-neutral reconciler (P3-7). The startup reconcile now honors
    storage.backend: on a Postgres vault it heals the Postgres store
    (previously it always opened the SQLite file, reconciling nothing real on
    PG vaults). wiki.ReconcileBackend is the new primary entry; the legacy
    Reconcile path is behavior-identical for SQLite (all existing call
    sites unchanged). Completes the graph storage
    backend seam — see .sage/docs/design/graph-storage-backend.md for the
    cookbook 3-table mapping, traversal rationale, and the Neo4j follow-on.
    Note: on Postgres, a contended writer open at startup stalls up to
    storage.lock_timeout then skips reconcile with a warning (never blocks
    startup).

  • /v1 REST facade + OpenAPI 3.1 + drift check (P4-1). sage-wiki is
    now callable from any language: 16 synchronous routes under /v1
    dispatch 1:1 to the existing MCP tool handlers (sage-wiki serve --ui),
    with a single JSON error envelope and fixed code vocabulary, structured
    /v1/status, edge validation for precise 400s, 412 feature_disabled
    pre-checks for as_of/mode=global, a 100 KB cap on capture (413), and
    Idempotency-Key replay on every write (in-memory, bounded — keys do not
    survive restart, documented). Auth reuses the existing Bearer + Host
    allowlist middleware; /api/* and all 18 MCP tool names are provably
    unchanged (regression tests). The hand-authored api/openapi.yaml is
    enforced against the registered routes and the tool registry by a new
    drift test (internal/api), including a self-test that proves it catches
    drift. Async job endpoints for compile/lint follow in P4-2. Guide:
    docs/guides/http-api.md.

  • Added the MIT LICENSE file (P4-0). The README has always said MIT but
    no license text shipped in the tree, leaving the default legal position at
    all-rights-reserved and blocking corporate adoption review. LICENSE is
    tracked in git, linked from the README's License section, and is picked up
    by the release workflow's existing [ -f LICENSE ] guard, so release
    archives include it from the next tag.

  • make ci now covers the translation-drift check. The documented local
    gate claimed to mirror CI but omitted MAINT-05, so a README.md-only change
    could pass make ci and still fail CI after merge. New make translations
    (same merge-base semantics as the CI job) and make translations-self-test;
    CONTRIBUTING documents the translations rule and the maintainer fork-PR
    workflow-approval step, and PRs get a checklist template. (#126)

  • pkg/sagewiki — in-process Go embedding (#112). A supported, non-internal
    entry point for embedding sage-wiki in another Go program without spawning
    sage-wiki serve as a subprocess. NewServer(projectDir) returns a handle
    exposing MCPServer() and Close(); pair it with mcp-go's
    client.NewInProcessClient to call the same wiki tools an editor integration
    calls over stdio. SetVersion lets an embedder report its own version string
    in the initialize response. The package is experimental while sage-wiki is
    pre-1.0: the Go signatures are meant to stay put, but tool names, argument
    schemas, and config.yaml layout can change in any release.

Fixed

  • MCP server reports the real build version. initialize returned a
    hardcoded 0.1.0 in serverInfo.version regardless of the binary's actual
    version; it now reports the -ldflags-injected build version (dev from a
    plain go build), mirroring internal/pack.Version.