Releases
0.38.1
Added
-
A website in
website/, built with Astro Starlight from the README,docs/and the bundle. Each concept page shows its trust label, sources and typed relations beside its own Markdown and JSON-LD, andwebsite.ymlpublishesmainto GitHub Pages with the four fileslokf exportwrites. -
docs/context-layer.mdplaces Knowledge Trust Ladder in the context-layer discourse. It quotes the people building context layers, shows one bundle as one repository’s layer, and sets out a design for federating bundles through domain manifests and a rebuilt workspace, drawn in two diagrams with the unshipped parts dashed.docs/context-layer-technology.mdsurveys the stores, catalogs, agent surfaces and artifact repositories it would plug into.
Changed
-
The research pages are trimmed to what KTL took and what remains.
docs/wikiskill.mdanddocs/skillwiki.mdkeep the changes each paper led to and drop the part-by-part comparisons;docs/skills-repositories.md,docs/context-layer.mdanddocs/context-layer-technology.mdlose the quotation surveys and keep the runs, the design, the status table and the decisions. -
The README, the sidecar’s README and ktl-librarian’s Golden Rule 1 link OKF’s specification in its own repository. Google moved the Open Knowledge Format to
GoogleCloudPlatform/open-knowledge-formatand froze the copy underknowledge-catalog/okf/. -
The website’s home page highlights Browse the bundle. It is now the first and primary button, and Quick start follows it as a secondary one.
0.38.0
Added
- ktl-prose writes for younger readers.
references/young-readers.mdgives two bands of age, 8 to 12 and 13 to 18, and a pass for dyslexic readers, with the limits of each. A text for a younger reader is a retelling in a new file, which ktl-librarian writes in the bundle and ktl-prose writes beside a file a person names; a pass for dyslexic readers is a rewording at tighter limits. - prose-check.py holds a page to a band of readers.
--audience 8-12,13-18ordyslexiasets the band’s limits, counts the sentences in each paragraph, and notes the page’s Automated Readability Index. A page that opens “This page is for readers aged 13 to 18.” is held to that band with no flag. - A band of readers is spared Latin abbreviations, and told which words may be hard. Under a band, prose-check.py reports
i.e.,vs,cf.,etc.andvia, and notes the words a page uses that the VOA Learning English word book does not hold. The word book is in the public domain and sits in the skill’sassets/folder with its credit. - prose-check.py proves that a retelling adds nothing.
--derived-from ADULT YOUNGreports a number, link, code span, quotation, HTML tag or fenced block that the retelling holds and the text it retells does not, and notes what it left out. The retelling’s first paragraph must link the original, and in a bundlederivedFrommust name the adult concept. - A README for readers aged 13 to 18.
README.en-simple.mdretells the README in shorter sentences,prose-check.py --derived-fromshows it adds nothing, and the README points to it. - A bundle can declare its younger readers. The curation policy’s optional
Younger readers:line names a band of age, andprose-check.py --bundlereports it asaudience: 8-12, oraudience: none declared. - The librarian retells, and the docent answers, for younger readers. ktl-librarian’s
references/retellings.mdsays how it writes and refreshes a retelling, and that a scheduled run retells only a confirmed concept, for a band the curation policy declares. ktl-docent and its Copilot copy prefer a retelling for a younger reader, or answer from the adult concept in shorter words, with every label kept.docs/examples/prose.mdcaptures the README’s retelling.
Changed
- The install commands install all five skills for your user. Both READMEs open with a Quick start that holds every install command, the docent alone included; it installs the whole set with
--global,docs/install.mdpasses--globaland--scope user, and a new section there says when a team installs into the repository instead. - A domain schema is one variable in the sidecar’s justfile. The
lokf-validateandlokf-check-refsrecipes passschema := ""as--schema, and the registrar, librarian and release workflows run those recipes, so a host wires a domain schema by setting that one line, by hand or through the linkml-sidecar skill.
Fixed
- A docs-only merge after a promotion no longer fails the release job. The version semantic-release computes is already promoted and waits for
publish.yml, so an empty Unreleased section passes and nothing is promoted twice. A failing check also writes its reason as a GitHub annotation.
0.37.1
Added
- The schema is the source of the class list and of the relation fields. Contract check 7c holds Rule 3’s class list to the classes
lokf vocab --all --jsondeclares as types, at the lokf floor the templates pin, where check 7 compared two prose lists with each other. Check 7d holds the relation fieldsknowledge-report.shcounts reliance from to the slots the schema ranges overConcept. Both run the toolkit throughuvxat the floor, so the comparison is against the schema a host installs. - ktl-sidecar’s portability page says what is tested before a release, and what stays with the host. The skills repository tests every template before a release, so a host whose copies are as the sidecar laid them down need not test them again. A copy the host edited, a port to another forge or shell, and another operating system stay the host’s.
Changed
-
ktl-docent follows all thirteen typed relations when it widens along the graph.
sameAs,measures,memberOfandholderjoin the list in its SKILL.md and in the Copilot instructions. A Metric now leads to what it measures, a Role to its organization and its holder, and a concept to one that says it is the same thing. -
The behavioural tests of the sidecar scripts moved out of the repository contract into
tests/, run with pytest.scripts/validate-repository.shheld about 2,000 lines of them beside the checks on this repository’s own files, each building a throwaway bundle or repository. Checks 8, 11 (its synthetic bundle), 11c, 12 (most of it), 12a, 13, 13a, 18 and 19 (most of each), 20, 20a and 22, andscripts/test-sidecar-layouts.sh, are now one module per script undertests/. The fixtures and the expected lines are the same. Each check’s number stays in the contract with a line saying where it went, so a changelog entry or a bundle concept that names one still points somewhere.validate.ymlruns the tests in a job of their own, withjustinstalled for the lokf-link recipe’s tests, andpublish.ymlruns them before a release. A test can be run alone, and the contract runs in seconds.
Fixed
- The report script counts reliance through
measures,memberOfandholder. The schema ranges the three overConcept, so a Metric relies on what it measures and a Role on its organization and its holder, but the count read ten fields and left them out. The three are in the list, in the template and in both copies, and ktl-curator’s trust-fields.md names thirteen. The template changed, so the siblings take it at the next sync.
0.37.0
Added
- ktl-librarian has a page for a host whose content is Agent Skills.
references/agent-skills.mdsays which skills are the host’s own, and leaves out installed and vendored ones. It asks a person about a skill under.claude/skills/that shows no sign of another home, and gives a skill template no concept of its own. It says what a skill’s concept holds, while the procedure stays inSKILL.md. A skill the repository deprecates stays a fact in the concept, apart from the curator’sstatus: deprecated. A miss that a skill’s own description should have prevented goes to the reviewer in a hand-off line, since only a person changes that description. The first run’s sweep table names Agent Skills folders. docs/skills-repositories.mdsays whether KTL helps a repository whose content is Agent Skills, read through WikiSkill and SkillWiki. It reports this repository’s own evidence, and a run of the sidecar, the librarian and the docent onanthropics/skillsat commit683bc88. It ends with the designs that remain, among them a record of skill runs and a trigger test.
Changed
- The threat model names a skills repository. There every source the librarian reads is a set of instructions for an agent.
docs/threat-model.mdsays which guards still hold, and that only the person reviewing a pull request catches an instruction that shapes what a concept says.
0.36.1
Security
- The provenance gate reads a
verifiedorgeneratedevent that spans lines, so a forged confirmation cannot hide in a multi-line flow layout. The hand-written readers inknowledge-provenance.shandknowledge-registrar.yaml’sprovenancejob parsed a flow event only on one line. Averified: [or agenerated: {continued on the next line is valid YAML every parser reads as a confirmation, but the gate saw no event and let an unsignedhuman:actor through, whereknowledge-report.shand the Obsidian plugins trusted it. Both readers now accumulate a flow event to its closing bracket. Checks 13a and 22 cover it. - The provenance gate reads a concept behind a byte order mark or in CRLF line endings, so a forged confirmation cannot hide behind one either. The same two readers keyed on a bare
---first line: a leading BOM (\357\273\277) or a---\ropener matched nothing, so the reader saw no frontmatter, read no events, and passed an unsignedhuman:event that every YAML parser strips the mark or the carriage return and reads. The readers now strip both before the opener, underLC_ALL=Cso a gawk in a UTF-8 locale reads the three BOM bytes as bytes, not as one character the strip would miss. Conventions already strips a BOM in the shell, and silently strips CRLF, so the gate was the only guard against the CRLF form. Check 22 covers a BOM-prefixed and a CRLF forgery. - The unattended provenance check follows a renamed concept, so a person’s text cannot be rewritten under a new name.
knowledge-provenance.sh --unattendedread a rename as a delete and an add and compared each path with its copy atHEAD, so a concept a person authored, renamed and rewritten in one change had noHEADcopy at its new path and passed. The check now pairs a rename by git’s own detection and compares the bodies. Verified against a rename-plus-rewrite and a rename-only control. - The pen refuses a provenance or event key in any case, and a top-level event field.
createandsetdeniedverified,statusand the rest only in lower case at the top level, so asetcarryingVerified:or a top-levelby: human:was written in, where the scheduled run’s own backstop grep then refused the whole run. The pen now matches those keys case-insensitively and refuses a top-levelby,atandrevision. Check 19 covers it. - The pen protects a curator’s send-back and will not glue a protected heading onto the line before it. A
resolveordeletecould remove aprocess:ktl-curatornote, the form a send-back takes when the curator could not sign in, and an edit ending exactly at## Open questionsor thelokf:relatedmarker merged that heading into the text. The pen now keeps such a note, and checks after each edit that a protected section is still there. Check 19 covers each.
Added
- Check 22 holds the gate’s event reader to a real YAML parser. It builds a human event in every layout a person might write (block, single-line and multi-line flow, a sequence, a mapping, an offset timestamp, an empty list, behind a byte order mark, and in CRLF line endings) and asserts the gate flags an unsigned one exactly when a parser sees one. So a layout one reader skips and the other reads cannot return as a way past the gate.
Fixed
- The report script reads every timestamp and event layout a YAML parser does.
knowledge-report.shdropped a+00:00offset, so an edited concept read confirmed by a person and a confirmed one read edited since; dropped a multi-lineverifiedlist, so a confirmation read nobody has checked; counted an emptyverified: [ ]as automation; and missed a concept behind a byte order mark.norm()now converts any offset across the day, month, year and leap years, and the reader accumulates a flow list or mapping and strips a BOM — byte-for-byte underLC_ALL=C, so a gawk in a UTF-8 locale reads the mark as bytes, not as a two-byte character it would leave in place. Check 20 covers each. - The report script counts an edited-since concept once, and reads a CRLF
index.md, a successor-less retirement and a subfolder sidecar. A concept edited after its confirmation whose source then moved was listed both on the work list and under a source moved after that confirmation; it now sits once on the work list, since the edit already overtook the confirmation.base_iriis read through a carriage return and a byte order mark, a retirement whose newest deprecation line names no successor reads as plain retired, andchangesreads a subfolder sidecar from the work-tree top. Checks 20 and 20a cover each. - The pen keeps a null value, writes atomically, scrubs a log line and a question, and clears a
./-led or#fragmentindex link on delete. A~,NULLor empty value no longer flips tonull. A write that fails partway leaves the bundle unchanged, each file staged beside its target and put in place only once all are written. Alogline and aquestionare scrubbed by Unicode category, as the hand-off is. Anddeletenow takes a link written with a./lead or a#fragmentout of a list of links, or refuses a sentence that holds it, rather than leaving it to dangle. Check 19 covers each. - ktl-prose skips an indented code block, reads a prose line that opens with an inline HTML tag, keeps an inline tag and a hard line break, reads a marker only where it opens a block, and notes a change of a fifth either way. An indented code block is code, so no style rule reads it. A prose line that opens with an inline tag is read with the tag masked, not skipped whole. A changed inline tag or a dropped hard line break is now reported, and a number that begins a wrapped line is checked as a fact, not a list number. The growth and shrink notes fire at a fifth, up or down, with no word floor. Check 18 covers each. (A rewording that swaps two facts from the same set is still passed by the token comparison and left to the reviewer, since the same comparison must pass a legitimate reordering of clauses.)
- The registrar scopes rule 14 to the pull request’s merge-base, the feedback script rejects a
.path segment, and both read login characters the same in every locale. Thevalidatejob passedbase.sha, whereprovenanceuses the merge-base, so a commit the base branch gained after the pull request opened could read as the pull request’s; both now use the merge-base.knowledge-feedback.sh --conceptrejected..but notplaybooks/./draft.md, which the report then never matched. Both scripts’ login checks now setglobasciiranges, a no-op where the shell lacks it. Check 12a covers each. - Contract check 15 reads the pinned skill path from the commit the pin records, not only from the tag ref. It used to skip when the tag was not on the clone, which on the scheduled, tag-less checkout was always; it now resolves the recorded commit and reads the path from it, and the tag-agreement half says whether that commit is a real object when the tag is absent. A fixture stages an untagged commit and reads the path from it.
- The layout tests no longer flake on a SIGPIPE race, isolate their git config, and leave no temporary files behind. A large
sedpiped intogrep -q, which exits on its first match, could take SIGPIPE and fail the check underpipefail; the sections are captured first. The fixtures run under an isolated git config, so a globalcommit.gpgsign=trueno longer signs them, and the extracted workflow steps write under the test’s own working directory.
0.36.0
Added
- Each skill’s page has a word budget. Contract check 10a holds every
SKILL.mdto one, set just above the page’s size. An agent loads the whole page when the skill starts, and the Agent Skills specification recommends under 5,000 tokens for it. ktl-librarian’s page, halved in 0.32.0, had taken back 328 words within two days. An edit that adds words to a page now moves as many into that skill’sreferences/, anddocs/repository-layout.mdnames the check where it gave token estimates. - The curator’s queue comes from the script.
knowledge-report.shreads every typed relation, in each spelling the format allows, and resolves its target as the KTL Curator plugin does. Its whole report prints how many other concepts rely on each concept, counting each citing concept once. It also prints the review dates due within 30 days, each confirmed concept derived from one edited after that confirmation, and Worth ten minutes today, ranked asreferences/trust-fields.mdsays. ktl-curator quotes that queue, where it used to count relations and sort them itself. Check 20a covers each spelling, a self-reference, a retired concept and a concept with noid. - A retired concept names what replaced it. ktl-curator’s Retire asks what replaced the concept, and its
**Deprecation**line inlog.mdlinks the successor after “replaced by”.knowledge-report.sh labelsthen reads retired, replaced by that path, from the newest such line, and only for a concept the bundle holds. ktl-docent, and its Microsoft 365 form, open the successor before falling back to the repository. LOKF has no typed relation for a successor yet, so the log holds the link, and nicholsn/lokf#112 asks for one. - A reader’s disagreement shows on the concept.
knowledge-feedback.sh --concept <path>names the concept a Disagreement disputes, right after the kind. It accepts the path only with a Disagreement, only in the bundle’s lowercase spelling, and only for a concept file that exists. Until the librarian handles the entry,knowledge-report.sh labelsadds a reader disputed this on that day, and the whole report lists the concept. The report reads the path and never the entry’s text. ktl-docent passes the path whenever a Disagreement is about one concept. - Conventions rule 14: a commit that records a person’s confirmation changes the verdict, not what the concept says. Rule 13 compares a confirmed concept with the commit that recorded the confirmation, so an edit made in that same commit read as confirmed, and only the person reviewing the pull request could catch it. With
--since <commit>,knowledge-conventions.shreads each commit after it against every parent, as theprovenancejob does. A commit that adds a person’s event no parent holds may change the concept’s claims only whengenerated.bynames that person, the shape of Correct now. The registrar’svalidatejob passes the pull request’s base, and a scheduled run passes none, since a squash merge folds an edit and a later confirmation into one commit. Check 11c covers each case, a merge among them. docs/skillwiki.mdreads the SkillWiki paper (Huang et al., 2026) and its code against this design, part by part: what KTL does with it, where the two designs differ, and what the paper does not settle.docs/wikiskill.mdnames the two papers apart, and the README credits SkillWiki.
Fixed
- ktl-curator’s two pages ranked its queue differently.
SKILL.mdput a confirmed concept whose source moved in the first group, andreferences/trust-fields.mdleft that case out. Both now give the order the script applies. The SPARQL query for the most relied-upon concepts counts each citing concept once, and never a concept for itself.
0.35.0
Changed
- ktl-prose lays out what it rewords the way the file’s project does. In a bundle that is one line for each paragraph, as ktl-librarian writes it, where the skill used to keep a concept’s old wrapping. Outside the bundle it keeps the host’s layout, and
references/rules.mdsets out the three layouts in use, with the benefit and the cost of each.
0.34.2
Changed
- The preflight reads the CI variables by indirect expansion, not
eval, so a scanner that searches forevalfinds none. Its output is unchanged, in bash 3.2 too. - The preflight names who needs a missing
knowledge-feedback.shorknowledge-report.sh: ktl-curator and an earlier ktl-docent, since the docent runs its own copies.
Security
- ktl-docent runs its own copies of
knowledge-report.shandknowledge-feedback.sh, never the repository’s. Anyone who can commit to a repository can change its.lokf/scripts/, so asking about a repository you had not reviewed ran its code. Check 11a holds the copies inskills/ktl-docent/scripts/byte-identical to the templates. The docent no longer runs the preflight: it reads a login fromghorglab. Without its scripts, it works out labels by hand, gives the reader the feedback line to file, and never writes.lokf/feedback.md. Its scanner note answers the Gen Agent Trust Hub audit of 2026-10-04. - ktl-docent puts the asker’s login in an entry only when the asker agrees. The scheduled workflow commits
.lokf/feedback.md, often into a public pull request, and git history keeps the line after the librarian clears it. - ktl-docent and ktl-curator keep only the
usernamefromglab api user, as the preflight did. Both gave the bare call as a login’s source, and it prints the whole profile, email and linked accounts included. - ktl-librarian and ktl-sidecar read the no-Python schema from a commit, not a tag, since a tag can be moved (Snyk W012). The URL names commit
66073c3, taggedv0.8.0, whoselokf.yamlis byte-identical to the schema in thelokf0.8.0 wheel that.lokf/uv.lockpins. Both skills say to read it as data, never instructions. Check 11b fails a tag or a branch in the URL, pages that pin different commits, and a page that does not name the floor’s tag.
0.34.1
Changed
- The Copilot docent’s gap report gives the librarian what ktl-docent’s does. A Miss starts with the reader’s question in quotes and says whether a concept looked relevant from
index.mdand did not answer, or nothing relevant was listed. A Disagreement says which version the answer gave. The skill also gives the source link when a question about the present rests only on an unchecked or edited concept, finds endpoints, versions and schemas as ktl-docent does, and takesktl-docent-m365as its heading.
Fixed
- The Copilot docent labels a concept as
knowledge-report.sh labelsdoes. Its rules reported every label that applied, most cautionary first, so a retired concept could also read as confirmed, and a concept edited after its confirmation could read as both. A retired concept now carries no other label, and edited since a person last confirmed it takes the place of confirmed by a person. Still a draft and then past its review date follow the first label, and a confirmation names the revision it was checked against. ktl-docent’sreferences/answering.mdgave the same rules for a sidecar with no script, and now matches the script too. - Every label table reads an empty
verifiedlist as nobody has checked this yet, as the report script does. The tables in ktl-docent, the Copilot docent and ktl-curator’sreferences/trust-fields.mdcalled it checked by automation only.
0.34.0
Added
- The librarian’s pull request says how the conventions script ended. The registrar’s gate does not run on a pull request the workflow opens, so
refreshrunsknowledge-conventions.shand the pull request reports the outcome beside the validation’s. The pen keeps most conventions by itself. Aresourcethat names no file and arevisionthat names no commit are the two only this script finds. knowledge-report.sh changessays what a change does to each confirmed concept. Each one it names is followed by still reads as confirmed, reads as edited since that confirmation, removed or its confirmation is gone. A check or a question on a confirmed concept was listed like an edit, so a reviewer could not tell which concepts lost their label.- ktl-prose rule 10 says where a text says a thing twice. “own” after a possessive, “itself” after a noun and “at all” after a negative are cut where they draw no contrast. A fourth pass, over the bundles of the three sibling repositories, cut 58 of 84 and 33 of 43. It cleared 305 of the script’s 312 findings, and the text grew by one word in a hundred.
prose-check.pycounts the words before and after a rewording. TheOKline of a comparison gives both counts, so the hand-off quotes them. A day or a month written out that changed, and a text cut by more than a fifth, are notes for the reader.- A scheduled librarian run opens no second pull request beside an open one.
knowledge-librarian.yamlhas a third job,earlier, which lists the pull requests the workflow opened, under a token that reads pull requests and nothing else. While one is open, a scheduled run stops before the agent. A week’s pull request left unreviewed was joined by another each Monday, each from the same default branch. A run a person starts goes ahead, and its pull request names the open one. - What a person declined is not proposed again. A pull request of the workflow’s that a person closed without merging left nothing the next run could read, so the same change came back.
earliernow hands a scheduled run a record of each: its base commit, the concepts it touched or added, and a hash of each feedback entry it handled.knowledge-report.sh quietcounts none of that as work, and the work list names it under Declined. Each item makes work again once it changes after that pull request. A run a person starts reads no record, so starting one asks the librarian to try again. - The preflight warns when git holds no
.lokf/uv.lockon a host that carries the registrar workflow, since the gate now installs from that lock.
Changed
- The pen refuses a patch that handles more than ten reader entries. ktl-librarian stated that limit for a run, and nothing held a run to it.
- The registrar’s gate and the release workflow install the toolkit with
uv sync --locked, as the librarian workflow did. A host whose.lokf/uv.lockis missing from git, or behind.lokf/pyproject.toml, now fails at the install step: runuv lockin.lokf/and commit the file.
Fixed
- The pen writes a value back as the file held it. It read each concept’s frontmatter into YAML’s types and wrote the whole block back, so
1.10became1.1,12:30:00became45000andyesbecametruein any concept it touched. On a person’s event an unquotedatcame back in another shape and an all-digitrevisionas another number. The gate read that event as changed, and the report script lost the confirmation’s date. The pen also refused an all-digit commit hash given asrevision. - The retrieval score leaves out a question whose concept has left the bundle. No index could lead to such a concept, so the question counted as a miss on every run. It is not asked now, and the score says how many were left out.
- Conventions rule 10 reports a comment beside
id,by,atorrevision. A parser drops the comment and a line reader takes it for part of the value. The gate then read an actor nobody is, and the report script could not read the time, so the concept never read as edited since. docs/wikiskill.mdsaid the paper’s wiki keeps every trace. Its raw layer keeps them, and the wiki’s log names the errors that came back.- A week is quiet again once the librarian has asked about a source it cannot act on. A confirmed concept whose source is deleted is the curator’s to retire, so the librarian can only add a question, and a question moves no stamp.
knowledge-report.sh quietkept counting that source, and an agent ran every week until the curator acted. A moved source no longer counts once an open question of the librarian’s that names it was committed no earlier than the source’s last change, and the work list names it apart. It counts again when the source changes after the question.
Security
- A person’s record is the same after the pen writes as before. The pen compares each concept it is about to write with the file it read, and refuses the patch when a
human:event or a person’s note would differ. Three patches passed its per-operation checks before: arewritewhose body brought its own## Open questionssection, a note in a person’s name spelt with an escaped line break, and adeletebehind a second heading placed above the real one.knowledge-provenance.sh --unattendedrefused each in a scheduled run, and nothing did in a live session. Check 19 exercises them. - A reader’s question and the hand-off hold no character a reader cannot see, whichever block it sits in. The pen and
publishlisted ranges, which left out the Arabic letter mark, the soft hyphen and the tag characters, which hide text from a reader and not from a model. The pen cleaned a reader’s question of control characters only. Both now go by Unicode category, as check 21 andprose-check.pydo. - The hand-off a reviewer reads is the pen’s, after the retrieval call too. That call carries readers’ words in its prompt and runs after the pen has written the hand-off, whose path it could write. The wrapper writes the pen’s lines there again once the call returns.
- A reply cannot add to what it is scored against. The retrieval scorer read the expected concepts and the reply from one stream. A reply that held lines in the scorer’s own shape raised both counts.
- The skill a scheduled run installs is pinned to a commit. The librarian workflow named a release tag, and a tag can be moved to other instructions, which an agent would then follow unattended.
TRUST_LADDER_SKILLS_SHAnow holds the commit that tag named when the pin was set, and the install step installs nothing unless the tag still names it. The release step andscripts/sync-sidecar.shmove the two together, and check 15 holds the template’s commit to its tag. - The conventions script and the pen pin PyYAML. Each ran through
uv runwith a barepyyamlin its dependency block, so the gate and the scheduled run installed whichever release was newest that day. The block now names one release, andexclude-newertakes no file uploaded after a set date.