Skip to content

Releases

0.54.0

Changed

  • The graph page keeps the graph at full height in full screen. Search and filters move into a side panel that scrolls, and switching between This bundle and The workspace draws the other graph in place, so full screen stays on.
  • The graph’s filters read as controls. Larger rows, a count on each entry, All and None on each group, and an “N of M concepts shown” line whenever a filter is off; every filter still starts on.

0.53.0

Added

  • The workspace counts the links between its members. The lock, the workspace index and queries/links.rq count the typed relations in one bundle whose target is a concept of another, by slot.
  • The workspace carries graph.json, every bundle’s concepts and typed relations as cytoscape.js elements. Each node names its bundle, and the links between bundles are marked.
  • The MCP server loads a member’s graph when a walk first reaches it, as section 11.4 of the LOKF specification has members load, and a SPARQL query loads them all. The lock’s graphs (format 4) says where each graph lies in graph.nq, with its digest, the namespaces it names and the IRIs it shares with another graph.
  • The federation build has the sensitivity gate of LOKF section 11.5. A member concept says public, internal or confidential: an internal member joins once a person confirms sensitivity: internal on the Domain concept, and only in a private or internal repository, a confidential one never, and the workflow keeps an internal workspace off the site.
  • A bundle that releases no zip joins by the concepts.jsonld its site serves, pinned by that file’s checksum; the build writes the file out as the bundle. The members script asks for it with a conditional request and proposes a changed file, and members --add <address> drafts such a member.
  • A member whose file cannot be fetched is held at its last good state, as section 11.5 of the LOKF specification has it, from the previous release’s workspace that --previous names. A release zip with other bytes is held only at the release a build fetched before, a member never built is left out until it can be fetched, and a check holds nothing its pull request proposes.
  • The readers read a workspace where it lies: a folder, a workspace-<tag>.zip in place, or the site that serves it, a graph at a time by range request. read_document reads the workspace’s copy of a release, else its concepts.jsonld, else its source, as section 11.4 chains them.
  • A reader can be given some members alone. --member <slug> on mcp, serve and query loads those bundles’ graphs and no other, and refuses the stored queries that read the lock graph.
  • A domain host’s release notes say what changed in its workspace. knowledge-federate.py diff compares two workspaces, and the federation workflow adds the members that joined, moved or left, and the links between them, to each release’s notes.
  • A domain host’s graph page draws the workspace. Its The workspace view draws every bundle the domain names, each in a colour and shape of its own, with the links between bundles dashed, from the graph.json the federation workflow serves. WORKSPACE in site.config.mjs turns the view on or off, and it is on when the repository has the workflow.

Changed

  • docs/federation.md holds the whole federation design, and states each rule once. Domains as manifests, LOKF section 11 and the release moved there from docs/context-layer.md, which keeps what a context layer is, the one-bundle table and what OKF leaves open.
  • The docs say the pen, its figure and the ingest’s guards once. The figure of who writes the bundle stays on docs/architecture.md, and docs/for-the-curious.md, docs/ingest.md and docs/three-lines.md link to the page that holds each detail instead of repeating it.
  • docs/context-layer-technology.md keeps to what KTL needs from a product. The vendor tables of limits, plans and quotes are gone, and the page names the sidecar’s own workspace server and MCP server beside the stores’.
  • docs/for-the-curious.md says how readers and verdicts steer the next run. It now holds what KTL took from the WikiSkill and SkillWiki papers, so docs/wikiskill.md and docs/skillwiki.md are gone. The bundle’s two concepts stay the record of each paper.
  • The federation build runs lokf in its own process. It exported and validated each bundle through a new lokf process, which imported lokf and LinkML again every time. A build of ktl-federation’s five members takes 4.5 seconds instead of 12, with the same output, and the federation tests run in half the time.
  • SECURITY.md and docs/threat-model.md say what holds after these fixes, with a section on the website, and no longer claim the most a hostile release could do before review was propose a change.

Fixed

  • The sync script no longer fails after a complete sync that replaces it with a longer copy. Bash read on into the new copy and ran a line from its middle, so the run exited with an error and the sync workflow opened no pull request. The script now exits on the line that calls main, a v0.52.0 copy also stops when it syncs to this release, and scripts/sync-sidecar.sh runs each sibling’s script from a copy.
  • A confidential ingest entry is refused where git could commit its copy. The script checks that git ignores .lokf/.cache/mirror/ and tracks nothing there before it fetches the entry.
  • The sync keeps a host’s .lokf/.gitignore current. A host kept the copy ktl-sidecar Step 1 first wrote, so it could lack the template’s later lines, such as .cache/, where a confidential copy goes.
  • The scheduled librarian stops before any agent runs when git does not ignore .agents/. It stopped only after the agent had run, at the write-scope check, with ?? .agents/.
  • The federation gate refuses a link into a member’s namespace that names no concept of that member, as --check-refs refuses one inside a bundle, under the same unowned_targets policy. It checked only that some member owned the namespace.
  • The federation gate reads a reified relations entry as it reads the slot that entry names, so a target no member owns there stops the build too. links.rq and unowned.rq count such entries as well.
  • The members script moves the other members when it cannot check one, which the hand-off names. When the GitHub API refuses a release list as rate limited, gh asks again with the job’s token.
  • The MCP server’s federated_sparql stops reading at its limit, 1000 rows or 2000 triples, and says when it cut an answer. It read a SELECT whole before cutting it, and returned a CONSTRUCT whole.
  • The workspace’s stored queries take their predicates from the toolkit. unowned.rq named owl:sameAs where lokf writes schema:sameAs, and left out memberOf and holder.
  • The graph page’s details panel sets each label beside its value. Starlight’s spacing for page content put every label a line below it.
  • A member whose index gives its licence as text, such as MIT, no longer stops the domain build. The lock graph keeps such a value as a literal, and the index writes it as text.
  • The MCP server reads a concept whose id lies outside its bundle’s namespace, which the registry routes through its id_index. It cut the IRI by the wrong prefix.
  • A member whose namespace nests with another’s stops the build with a finding that names both, before anything is fetched. The registry refused it only after every download, with a Python traceback.
  • A checksum must be sha256: and 64 hex digits. Only its length was checked, so a path in it could reach outside the download cache and have the build delete a file there.
  • Every download stops at --max-bytes, a member’s schema and workspace as well as its zip, where each was read whole before its checksum was compared.
  • A download is tried again after a server error or a dropped connection, and follows a redirect only within http and https, never from https to http and never from a public address to a private one.
  • A zip of more than 100,000 entries, or one that matches its checksum but cannot be read, stops the build with a finding, where it filled the disk or ended in a traceback.
  • A reader keeps no partial answer to a range request as the whole file, and --previous refuses a site address, from which no zip member could be held.
  • The federation workflow’s weekly schedule no longer takes the place of a release build that waits for its turn, and each job has a time limit.
  • A domain host’s site serves each member’s release inside the workspace. The Pages upload left out the hidden bundles/<slug>/.lokf/ folders, so every member link in the served workspace index answered 404.
  • The contract records every sibling host’s links into this repository, among them ktl-federation’s into the federation page and the domain-bundle playbook. Its local cross-check reads all five hosts, and skips a domain host’s ignored snapshot/, which holds a copy of this bundle.
  • The librarian keeps run accounts out of the source map. No rule asked for one, yet each refresh had added its account to playbooks/knowledge-sources.md, 41 of them by 2026-10-19. The skill now says the map holds none.
  • An agent that applies its own patch no longer loses a scheduled run’s work. The wrapper sets KNOWLEDGE_PEN_DRY_RUN_ONLY for the agent, so the pen only checks the patch file there and leaves it for the wrapper to apply. The skill and the pen’s dry-run line no longer tell a scheduled agent to apply and validate.

Security

  • A release can no longer write a host’s git configuration through the sync. knowledge-sync.sh refuses a copy path inside a .git folder and clones the release without a checkout.
  • The branch the sync pushes carries no workflow a release wrote. A workflow on a pushed branch runs with the repository’s secrets, so publish applies the patch with knowledge-sync.sh --apply, keeps every workflow but for the pin, and holds the release’s workflow changes for a person, or for a reviewer of the Environment KNOWLEDGE_SYNC_REVIEW_ENVIRONMENT names.
  • The sync’s publish refuses a deletion, a link or an unusual mode, and leases its push to the commit it read. A branch holding a person’s commit is left alone with or without a pull request, and the report names a manifest rule the script does not know.
  • Each workflow reads its secrets from an Environment limited to the default branch: knowledge-librarian, knowledge-sync and knowledge-ingest. Move every repository secret there on every host, as the sidecar’s references/automation.md says.
  • A federation build refuses a member zip holding a hidden file or a file a browser runs, and a distribution name that is not one plain file name. A .git folder in a zip, or a name that climbs out of the workspace, could run code in the build; the health line now runs git on no member’s folder.
  • A federation build fetches members over http or https from public addresses only. --allow-local allows local paths and private addresses, and a person’s private_addresses: allow on the Domain concept allows a forge on the host’s own network.
  • A member’s attestation must come from its own release workflow, or its federation workflow for a workspace, and a build without gh stops unless given --no-attestation.
  • The federation workflow hands its token to gh alone, and the website and federation builds run no npm install script.
  • The website copies only files inside the repository, and passes raw HTML as GitHub renders a README. A link out of the repository and an SVG holding a script are left out, other markup is shown as text, and Astro’s telemetry is off.

0.52.0

Added

  • A member that waits in a member domain joins at the release that domain built. The members script now names a member domain’s released workspace-<tag>.zip and its checksum in the MemberDomain concept. The build then takes such a member at the release the lock inside that zip records, and the lock names each member concept (format 3). A member names the files of one release, and the build refuses a schema or workspace from another.
  • knowledge-report.sh coverage --why <path> names the concept that claims a file, directly or through a folder above it, so a reviewer can find the row of the source map that excludes it. It reads frontmatter only.
  • coverage --strict exits 1 when a tracked file is named by nobody. It also fails on a folder that holds no tracked file, such as a mistyped one, and when it cannot count, so a check built on it never passes by default.

Changed

  • coverage counts apart the files git would add. A concept names only a path git tracks, so a new file shows with the advice to commit it, or to ignore it if it is runtime state. A tracked file deleted from the working tree no longer counts.

Fixed

  • The federation check runs the gate as the next release build would. build --verify-only stopped after the zips, so a pull request with a link into a namespace no member owns, or into a member no person had confirmed, passed and the release build after the merge failed. The check now exports, loads and gates the bundles without writing anything, names the members the next release would leave out, and runs on any change to the domain bundle.
  • coverage . lists every file nobody named, and a mistyped folder says git tracks nothing there. Both printed “none”, which read as fully covered. A flag coverage does not know is refused instead of being read as a folder.

0.51.0

Added

  • A person who sends back text they wrote can release it to the librarian. ktl-curator then writes process:ktl-curator in generated, in a commit that person signs, so the librarian’s next run rewrites the text from its sources instead of only adding a question.

Fixed

  • docs/three-lines.md no longer lists the lokf-registry MCP server as a design. knowledge-federate.py mcp serves it, as docs/federation.md says.
  • Conventions rule 2 holds every at: to one shape: UTC to the second, as date -u +%Y-%m-%dT%H:%M:%SZ writes it. A time with a lower-case t or z, an offset or a fraction passed the gate. The report script, the federation build and the workspace’s stored queries did not all read such a time the same way. A person’s event that no script could read counted as confirming every later edit.

0.50.1

Fixed

  • The federation build leaves out a concept a curator retired. A retired Domain concept no longer counts as a second top, and a retired member is neither built into the workspace nor moved by members. The curator’s domain-bundle.md says how a member leaves.
  • The federation build takes each member as a person last confirmed it. It built every member concept on the tag, so a merged move or a new member joined the workspace before anyone confirmed it, against the federation design. A moved member is now built at the newest release the default branch held confirmed, while that confirmation stands, and a member no person confirmed is left out. The lock and the workspace index list both as waiting.
  • The Domain concept’s gate policy and depth count only as a person confirmed them. An edit no person confirmed waits, and the defaults stand in until a first confirmation.
  • The gate names a member that waits. A link into the namespace of a member left out for want of a confirmation is reported with that member, and an error about a release a person confirmed earlier says which newer one waits.
  • members --add quotes the description in the new member’s own index. It pasted the description after a colon, with no full stop when the description had none, so the next sentence ran on.
  • The sync calls a copy a pin bump only when its uses: lines are all that differ. It reported every copy the release changed as “differed only on its action pins”, because under pipefail its test took diff’s exit status.

0.50.0

Added

  • The ingest restores a lost mirror file and prunes on a schedule. A file the lock names and the disk has lost is fetched again and reported as restored. A scheduled run removes a gone or unlisted file no concept cites, once an earlier run recorded it so, and the preflight counts missing, stray and prunable files.
  • docs/ingest.md has a figure, .assets/ktl-ingest.svg with its dark variant: the sources, the ingest, the review and the concept that cites the mirror.

Removed

  • The figures nobody shows. Every -dimmed figure, unreferenced since the dark theme moved to the -dark set, and both files of the lifecycle loop, which no page has shown since the README dropped it.

0.49.0

Added

  • The ingest mirrors knowledge from outside the repository. knowledge-ingest.py, a new ktl-sidecar template with a shell half, reads .lokf/ingest.yaml, fetches the sources it names, converts each to Markdown and writes it under .lokf/mirror/, with .lokf/ingest.lock.yaml recording the version, the digest and the status of each. Four kinds: a Confluence selection, a list of addresses, a path in another repository at a ref, and a command the host committed. The librarian derives concepts from a mirror file as from any tracked file, so nothing in the trust ladder changes.
  • knowledge-ingest.yaml opens one pull request with what changed. It runs the host’s own script with the repository secrets whose names start KNOWLEDGE_INGEST_ in a read-only job, and a separate job commits the mirror and the lock to the branch knowledge-ingest, refreshed until merged; .github/PULL_REQUEST_TEMPLATE/knowledge-ingest.md is the reviewer’s checklist. KNOWLEDGE_INGEST_ENABLED turns it on.
  • docs/ingest.md is the guide: the manifest, the mirror, the lock, the secrets, what the pull request shows and what the librarian does next. The preflight prints an ingest line, and knowledge-report.sh coverage counts the mirror’s files.

Changed

  • A domain concept is named for the domain, never for its position. The curator’s domain-bundle.md says so, its worked example names ktl-federation’s domains/ktl-federation, and it says a confirmation stays with the concept’s id.

0.48.0

Added

  • A domain may name domains, tier by tier. knowledge-federate.py build follows a member whose released bundle is itself a domain as deep as the top Domain concept’s max_depth allows, 3 unless set, and domain.yaml adds max_depth and a MemberDomain class so a manifest says which members are domains. The lock records each member’s tier and every domain that named it, and the workspace index says who named each.
  • The diamond rule. A bundle two domains name at the same release joins the workspace once, and the lock records both; at different releases the build stops, because one named graph holds one release. members --add drafts a MemberDomain when the release it admits is a domain.
  • docs/federation.md takes the federation’s mechanics out of the context-layer page. It holds the tiers of domains with the figure ktl-federation-tiers.svg, how the workspace stays current, what exists today and the decisions, two of them new: namespaces that mirror the tree, and what a member adds. docs/context-layer.md keeps the discourse, the one-bundle table and the design.
  • knowledge-report.sh coverage counts the tracked files no concept names. Per top-level folder, the files under no path a concept names in its resource or sources, and the list under a folder you name: ktl-librarian’s sweep for orphans as arithmetic, where a folder the source map names is accounted for and the map’s row says why it is left out.

Changed

  • The website’s figures stay in the text column. On a wide screen a diagram no longer grows into the main pane’s spare width; a click opens it at full size. The change is in the template’s theme.css and Mermaid.astro, so a host gets it with its next website repair.
  • The sidecar’s pages name Codeberg beside GitLab, Forgejo and Gitea. The install, signing, automation and scheduled-task pages point at the portability recipe for another forge, and the registrar template’s header links the three-lines page through w3id.

Fixed

  • Two tiers may each name a members/<slug>.md. Each bundle keeps a folder of its own under bundles/ and export/, and none can take the domain’s own domain folder.

0.47.0

Added

  • A host keeps its sidecar current by itself. knowledge-sync.yaml, a new ktl-sidecar template, reads the skills pin and the newest release each week. When the pin is behind, it runs the host’s own knowledge-sync.sh in a read-only job and, in a separate job, opens one pull request from .github/PULL_REQUEST_TEMPLATE/knowledge-sync.md with the KNOWLEDGE_SYNC_TOKEN secret, or attaches the change to the run without it. The pull request stays one, refreshed to the newest release each week until it is merged. publish.yml asks the hosts named in KNOWLEDGE_SYNC_HOSTS to sync as soon as a release is tagged.
  • knowledge-sync.sh is the sync, as a sidecar script. It copies a release’s templates over a host’s copies, moves the pin, writes the changelog entry under ## [Unreleased] and ### Security, runs the sidecar’s checks, and takes the sync to a pull request with --commit, --push and --pr. Without --source it clones the tag.
  • templates/knowledge-sync.manifest lists what a sync keeps current. Each template, its copy and the rule for it, in one list that the sync script, the preflight and contract check 11 read. So a release is data to a host’s sync, and no code from it runs there.

Changed

  • scripts/sync-sidecar.sh runs each sibling’s own knowledge-sync.sh, or the tag’s in a sibling that has none. It takes --commit, --push and --pr, and --finish <tag> puts each sibling back on its default branch and removes a merged sync branch. The entry links the comparison between the two pins, so a sync that skipped releases points at all of them.

Fixed

  • knowledge-federate.py members verifies attestations under the librarian wrapper. The wrapper strips every token, so gh attestation verify failed; the script now takes the job’s read-only token as KNOWLEDGE_FEDERATE_TOKEN (AGENT_USE_JOB_TOKEN true, AGENT_API_KEY_ENV set to that name), hands it to gh alone, and says which variables to set when it has no credential.
  • The sync writes the changelog entry instead of printing it with a hint. The hint named ### Security with a sentence’s colon after it, and a heading typed that way once failed the lint.

0.46.0

Added

  • knowledge-federate.py mcp serves a workspace to agents. It is the lokf-registry server the LOKF specification’s section 11.4 describes, over the snapshot: resolve_iri, neighbors, subgraph, federated_sparql and read_document, each bounded in depth and size, with the workspace index as the server’s instructions so an agent reads it first. serve, query and mcp take an absolute --snapshot, so an unpacked workspace-<tag>.zip is read anywhere a sidecar environment exists.
  • knowledge-release.yaml attaches the domain schema the justfile names. schema-<tag>-<name>.yaml goes beside the bundle zip with its own .sha256 and attestation, so a federation can validate the bundle on its own terms. knowledge-federate.py names it as a second distribution when a member moves, and the build validates that member against it instead of LOKF core alone.
  • knowledge-federate.py members --add <owner>/<repo> drafts a new member. It verifies the repository’s newest bundle release, reads the bundle’s namespace and title from the zip, refuses a namespace that nests with a member’s, and writes a create with a question for the pen.

Changed

  • The sidecar’s llms.txt and README aside no longer assume npx skills works. The agent context offers the GitHub CLI route beside it and says when a company proxy blocks the other; the README aside points at the install page.

Fixed

  • The workspace registry no longer names the runner’s own folder as the domain’s source_base. The domain’s entry now points at the host’s repository at the tag, or at the served copy of the unpacked bundle, and the index names the address that is served (.../workspace/index.md) rather than a folder that answers 404.
  • postcss-selector-parser 7.1.6 in the website template’s lockfile (GHSA-rj75-hqrm-r3gf, quadratic selector parsing), and in this repository’s own site.