Two gaps. Format was decided inline in the import command by whether the text
started with a brace, and --source only ever reached the CSV reader -- so a JSON
or archive export could not be forced at all. If the sniff was wrong there was no
way to say "this came from 1Password". And 1Password's own export button produces
a .1pux, which nothing here could open.
A source now names a product rather than a file format. Bitwarden exports JSON
and CSV; 1Password exports .1pux and CSV. Saying --source onepassword says where
the file came from, and the container is still decided by looking at the bytes.
One router owns that decision instead of the command, and when nothing can read a
file it prints every source that can be named rather than the bare "pass
--source" it used to.
1Password's .1pux is a ZIP holding a single JSON document. Pulling in a zip
library for that would have been this package's only dependency beyond commander,
so the central directory is read here: node's zlib already does the
decompression, and the container is a few dozen lines of offsets. Deliberately
not a general ZIP implementation -- no encryption, no ZIP64, only the two
compression methods an export uses.
The .1pux reader keeps vaults as folders, TOTP secrets, custom sections, password
history and the whole of a card. 1Password item ids are 26-character base32
rather than UUIDs, so they are hashed into a v5-shaped UUID: the same export
imported twice produces the same ids, which is what makes a re-import report its
items as already present instead of duplicating the vault. Trashed items are left
behind and reported, since restoring deleted entries into a fresh vault would be
a surprise. A category we do not model -- a passport, a server, a licence --
becomes a note carrying its fields, so an import never quietly loses one.
Six more CSV products join the existing five: NordPass, Dashlane, Proton Pass,
RoboForm, Apple Passwords and Firefox. Adding Apple broke 1Password: their
columns are nearly identical and only 1Password's `type` separates them, so Apple
now requires its absence and 1Password is asked first. There is a test for that
pair, because the failure mode is silent -- every 1Password CSV had started
importing as Apple.
LastPass and KeePass needed nothing: LastPass only ever exports CSV, which was
already read, and the same is true of KeePass's CSV.
Verified end to end: the real 4,395-item Bitwarden export still reads, a .1pux
round-trips through the CLI, an unidentifiable CSV prints the source list and
then imports once told, and an unknown source name is refused by name. The zip
reader is tested against archives the system zip produced rather than ones we
wrote. 195 tests pass.
The 1Password mapping is built from the documented 1PUX schema and driven by
fixtures, not from a real 1Password export. Run it with --dry-run first.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four things the first pass threw away, all of them recorded in the mapping notes
from the 2026-09-02 hand conversion and all of them silent.
Item ids were regenerated. Bitwarden ids are already UUIDs, so keeping them is
what makes a re-import idempotent: run the same export twice and the second run
reports its items as already present under "skip", rather than duplicating the
entire vault. createItem deliberately refuses a caller-supplied id and always
mints a fresh one, so the id is adopted after construction, and only when it
really is a UUID.
Timestamps were restamped to "now". creationDate and revisionDate are the only
record of when a password was last rotated, and overwriting them destroys that
permanently. The oldest item in a real export dates to 2018; every one of them
would have been dated today.
Password history was dropped entirely. It is carried now, newest first, mapping
lastUsedDate to changedAt and capped at MAX_HISTORY_ENTRIES. 189 items in a real
export have history, so this was not a rare case.
URI match rules were hardcoded to "domain". Bitwarden stores them as a number --
0 domain, 1 host, 2 startsWith, 3 exact, 4 regex, 5 never, with null meaning
domain -- and flattening them quietly widens a login pinned to an exact URL,
which is a security change rather than a cosmetic one.
Verified on the same 4,395-item export: all 4,395 ids carried across, stable
across two runs, 189 items with history recovered, and the oldest createdAt still
2018-02-22. That export happens to use domain matching throughout, so the match
mapping is covered by tests rather than by it.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Importing a Bitwarden export failed with "Not an OpenCreds database" and had to
be converted by hand first. The import command decided what a file was by
`text.trimStart().startsWith("{")`, and treated every JSON as an OpenCreds
database. A Bitwarden export starts with a brace too, so it went to parseDatabase
and was rejected there.
JSON is the format Bitwarden's own UI hands you by default, and the only one of
its formats that keeps folders, custom fields, multiple URIs per login and full
card/identity detail. Its CSV drops all of that, so "export as CSV instead" is a
lossy workaround rather than an answer.
The shape is now sniffed before deciding which reader owns the file: an `items`
array plus either a `folders` array or the `encrypted` flag. An OpenCreds
database has neither at its top level, so the two never collide, and a cheap
substring test means a large database is not parsed twice to find that out.
Everything the format carries is mapped: all four item types, Bitwarden's own
folder ids (so two folders sharing a name stay distinct), custom fields with
their hidden flag, every URI rather than only the first, TOTP secrets, and
favourites. An untitled login is still named after its host. A folderId naming no
folder is dropped rather than inventing a folder, and only folders something
actually landed in come back, so importing one item out of a big export does not
create sixteen empty folders beside it.
An encrypted export is refused outright instead of half-read. Its items are
opaque strings, so a best-effort parse would store ciphertext as if it were a
password and leave a vault full of junk that never decrypts.
Verified against a real 4,395-item export: 4,387 logins, 3 cards, 4 identities,
1 note, 16 folders, zero skipped, parsed in 56ms. Every count matches the source
file, and the command that used to fail now reports "(Bitwarden JSON)".
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
All 3,963 emoji (previews 64/128 and openemoji.json with CLDR keywords
and oe_ shortcodes), and platforms.json: 23 networks, 324 packs, steps
and limits, downloads from the openemoji release. The catalog's Install
on picker appears with it.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Reddit, Slack, X and Facebook read og:title, and every page of
logicsrc.com was serving the homepage's. The <title> tag was correct per
page, which is why it went unnoticed: Next.js shallow-merges metadata, so
a page exporting only `{ title, description, alternates }` inherits the
root layout's `openGraph` object whole. og:title, og:description and
og:url were the homepage's on all 45 spec landing pages, every doc, every
report and every SPA section.
Blog posts were the one route that declared openGraph, and they proved
the mechanism: their og:title is right. They also showed the other half
of it -- declaring openGraph drops the file-convention opengraph-image,
so live posts shipped with no og:image at all, and their twitter:title
was still the homepage's.
- src/lib/page-meta.ts: one builder, three entry points. specMetadata
titles a spec landing page from its lib/specs.ts entry, pageMetadata
titles the site's own pages from PAGE_META, contentMetadata titles a
doc, post, skill or ontology record from its content. All three always
emit openGraph and twitter title, description, url and image.
- Spec titles come from the registry, so they cannot drift from the way
the sidebar, /specs and the home page describe the same spec, and a new
spec page is titled the moment its registry entry exists. composeTitle
trims a long subject line at a clause boundary to fit a link preview.
- Doc pages carry that subject line too, because every spec's H1 is just
its name: "OpenStream" alone was the whole title.
- docExcerpt joins the wrapped lines of the first real paragraph and
skips Status:/Slug: headers and list lead-ins, so descriptions stopped
being "Status: 0.1 draft" and "Core tables:".
- contract/page-metadata.contract.test.ts fails if a sitemap route has no
title, if a spec page has no registry entry, if two pages share a
title, if a page declares metadata without the builder, or if a page
loses its social image.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
openicon.json with the hq block, 259 full-colour UI icons as WebP 64/128
and 111 brand SVGs in their owners' colours. The gallery's Simple/HQ
toggle appears on its own now that icons carry hq.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* OpenEmoji catalog: browse and install by network
Reads platforms.json from the set: a network picker grouped by kind
(custom emoji, sticker packs, images to post), and for the chosen
network its verified limits, install steps, packs with sizes, Show (in
the grid) and Download (release assets), the grid narrowed to what its
bundles hold with each emoji's name on that network, and the detail
panel saying which pack holds it. A network that names what it is for
opens on it: X opens on country flags.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* OpenEmoji catalog: previews for 2,424 drawn glyphs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A set may add a full-colour HQ style beside the canonical simple one:
styles: [simple, hq], a top-level hq block (sizes, webp_sizes, provenance,
coverage) and an hq block per icon (png, webp, svg for brands, made_by,
hex, hex_source). Same silhouette as simple, falls back to simple, brand
colour must be the owner's with its source, provenance is per style.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replaces the 47-icon sample with the whole reference set: search by name,
alias or keyword; category chips with counts; UI/brand filter; SVG,
Nerd Font, Unicode or ASCII view (the Nerd Font view uses the official
symbols subset to the set's 349 glyphs, 38 KB woff2, MIT); size and
colour; a detail panel with all three glyphs and codepoints, trademark
notes, copy SVG / <img> / icon("key"), and downloads. Ready for the
optional HQ (full-colour) style: a Simple/HQ toggle appears once icons
carry an hq field. Filters live in the URL.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
One openicon.json naming every icon (kebab-case keys, unique aliases,
shared keywords), 24x24 currentColor SVGs with a stated grid, and three
terminal glyphs per icon: a Nerd Font character with its codepoint and
glyph name, a Unicode symbol and a 1-4 character ASCII spelling, picked
nerd > unicode > ascii. Brand logos carry brand: true, a trademark note,
source and licence. made_by + W3C AI disclosure per set and per icon.
Mapping from Lucide, Tabler, Font Awesome, Nerd Fonts and Simple Icons.
Landing page shows 47 icons from the reference set (profullstack/openicon).
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* OpenEmoji catalog: every emoji in the reference set, with search and filters
/openemoji/catalog reads the set's openemoji.json (every Unicode emoji,
drawn or not) and filters by name and CLDR keyword, group, subgroup,
skin tone (keyboard-style swap), Emoji version and status, with sort,
tile size, URL-synced filters, paged rendering and a detail panel
(codepoints, tone family, copy, PNG/SVG downloads, keyword chips).
Spec: an entry without files is listed, not drawn.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* OpenEmoji catalog: reference set previews, first 206 glyphs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
One openemoji.json that states coverage against a Unicode version, the
licence, and who or what drew the set (made_by plus the W3C AI disclosure
vocabulary), and glyphs named by fully-qualified codepoint sequence.
Custom emoji get x- keys with shortcodes; skin tones name their base;
rendered emoji keep the character as alt. Mapping from Mastodon, Slack,
Discord and CLDR.
Landing page shows 19 glyphs drawn by the reference implementation,
`emoji` in profullstack/cli-tools.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every secret now has a category derived from its name (db, social, server,
api, cloud, finance, crypto, ai, email, messaging, storage, dns, analytics,
devtools, auth, config, other). One rule table in @logicsrc/opencreds serves
both vaults; services win over generic words, so STRIPE_WEBHOOK_SECRET is
finance, not auth. Checked against the 1,208 distinct key names in the
profullstack team: 74 fall to "other".
Team vaults (where the shared .env secrets live):
- teams categories [team] the filter words, with per-category counts
- teams secrets <team> [project] [env] --category/-c --search/-s
names + categories, never decrypts; --format csv
- teams export <team> [project] [env] --category -o file.csv [--yes]
decrypts into team,project,env,category,key,
value,updated_at (0600); skips vaults without a
grant and names them
Personal vault (OpenCreds):
- vault list --category, and the category column in list output
- vault export --format csv: one flat row per item, keeps key/account
secrets that a Bitwarden CSV drops; --category on every export format
DX:
- examples in `logicsrc vault help` / -h / --help that start by saying which
of the two vaults you want, plus examples on teams and each subcommand
- password prompts go to stderr, so eval "$(logicsrc vault unlock)" works
- hints name the command you actually ran (logicsrc vault init, not
opencreds init)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
TITLE / STYLE / EXCLUDE STYLES / LYRICS label blocks with [Section - direction]
tags, no Markdown (Suno reads plain text only). Kept beside the audio as the
same name with .txt, album lyrics.txt with ==== dividers, one-way mapping to
ID3/Vorbis tags. Example is track 002 of Þrøngva, When the Ravens Lied.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A Power Key bought once at profullstack.com/shop now opens this site:
the gateway verifies it offline with @profullstack/keys and treats it
as a pass, so it is never charged as a crawler or metered. The 402
body and the sales page point at the shop.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
OpenObject is a bucket you can mount: keyed objects as ipfile swarms placed
on OpenDisk disks under pay2seed at a stated redundancy (three replicas on
three operators in two countries by default), an ipdb index as the bucket's
clock, a repair loop, an HTTP API, an S3 mapping and a mount whose
consistency is close-to-open by seq. d1sks.com is the reference store.
OpenSlice is a container whose compute is rented from one market and whose
disk is mounted from another: a host descriptor at
/.well-known/openslice.json, one signed slice file (image by digest,
OpenCPU/OpenMemory/OpenGPU units, OpenObject mounts, OpenCreds env, ports,
placement, lifetime), and a reservation that is a paid2seed lease applied to
compute with presence proofs per epoch. slic3s.com is the reference
marketplace; c0mpute hosts take the slice role.
Both are registered under OpenServer in the catalogs family with landing
pages, rows in the OpenSwarm family table, and the spec-discovery contract.
llms.txt now cites the specification URL for child specs too, which every
block under OpenServer had been missing.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A new LogicSRC spec in the catalogs family. One heading, an identity block
(Kind, Web, Repo, Operator, License, Extends, Updated), one line, then eleven
layers: Languages, Runtimes, Interfaces (one ### per way in: web, api, cli,
tui, mcp, desktop, mobile, worker, extension, bot), Data, Services, Modules,
Tooling, Hosting, Auth, Conventions, Not. An item is one bullet: name,
version, an optional status word (trial, hold, leaving) and a role. Extends
inherits a parent file, sections replace, Conventions and Not accumulate.
Rule 8 is the reading rule for agents: use what is listed, prefer listed
over new, ask before adding a layer or a service, never add a Not, keep the
file true. Discovery at OpenStack.md in the repo, /.well-known/openstack.md,
rel=openstack, or a platform path. JSON is derived and never the source.
logicsrc.com serves its own at /.well-known/openstack.md: the route extracts
the worked example from docs/openstack.md, and a contract test holds the two
together and checks the file follows its own rules. rel=openstack in <head>
and in the Link header beside openprofile.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The W3C AI Content Disclosure community group defines four attributes,
not one: ai-disclosure, ai-model, ai-provider and ai-prompt-url. Both
specs carried only the first, as `disclosure`. They now carry all four,
as `disclosure`, `ai_model`, `ai_provider` and `ai_prompt_url`: which
model, whose, and a page describing how it is used, optional and
meaningful only beside a disclosure other than none. `mixed`, the value
the group's meta tag form allows, is accepted at the site level in
OpenWebring and the page level in OpenWiki.
A ring host copies all of them into the member entry as the member said
them. A wiki carries them on the page and per revision, and a host
rendering a page puts the same four on it as the group's meta tag and
attributes. Both specs are 0.1.1; the wire version stays 0.1, since every
field is additive and absent is still unstated.
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
OpenWiki writes down what the [[Page]] convention already is in practice,
so a wiki can be moved, mirrored, read by a directory and edited by an
agent without reading any engine's source. One Markdown file per page
with a small optional front matter (title, aliases, tags, summary,
author, made_by, disclosure, created, updated, license, lang, redirect);
wikilinks resolved by exact name, loose name, alias, path, then wanted;
one address with three representations (rendered, .md, .md?rev=) and a
history.json per page; a descriptor at /.well-known/openwiki.json with
pages_url, changes (Atom), repo, edit, editors and accepts; editing as
PUT of the same file with If-Match on the revision; discovery; what a
directory owes a wiki. Every revision says who made it: human, ai or
both, the same word OpenWebring uses.
A folder that follows it opens unchanged in Obsidian and Logseq, and any
such folder becomes an OpenWiki by adding the two files. The first host,
goviral.wiki, is being built on it.
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Manual publish of the report attached to the nixamp v0.24.2 release
(openstream-report-0.24.2.json/.md). The release workflow's
publish-report job skipped because LOGICSRC_PUBLISH_TOKEN is not set
on profullstack/nixamp. Built-in synthetic corpus, so the id carries
the -synthetic label per docs/openstream/reports/README.md.
Claude-Session: https://claude.ai/code/session_015uheT4Gn9BBKAnSZGcabyN
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
OpenL10n is the record of what a file says, in any language: one
transcript per media per language, addressed by the OpenFile id (or a
url: or live: identity for what has no bytes), lines as seconds into the
media, a translation kept beside the original and marked with what it
came from, complete or heard in pieces, made once on request with 202
progress, served as JSON, SRT, VTT or text.
OpenI18n is one file a service serves at /.well-known/openi18n.json
about the languages it speaks: which, which it can turn into which, how
to ask for one, and where texts are translated, with limits, models and
the pivot said out loud.
Both are what nixamp 0.24 and 0.25 serve today, written down so anything
that hears or translates can keep the same record.
Claude-Session: https://claude.ai/code/session_015KAKuRngFbQg3kET6RS5yN
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The spec and its landing page now name the directory that reads every
OpenWebring host: one row per ring and one per member, with made_by as
the member said it and the status the host last verified, re-read hourly.
The first host line also names rssamplifier's curated Profullstack ring.
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* OpenFleet reference implementation: @logicsrc/openfleet 0.1.0 and logicsrc fleet
Ship what docs/openfleet.md describes. The new workspace package holds the
record (write once, never overwrite, 0600), the ledger (append-only JSON
Lines, merged across ledger*.jsonl by at), the ceiling rules (whole fleet
ceiling, narrowed swarm keys, a merge that never widens, refusals by key),
claiming and deriving exactly as the spec's "Claiming and deriving" and
rule 13, and fold(), which turns any $OPENFLEET_HOME plus the engine
rosters into the tree the landing page shows.
logicsrc fleet open|cap|tree|stop|log are the sysop's verbs, every one with
--json. open and cap exit 4 when OPENFLEET_MEMBER is set; stop exits 4
outside the caller's subtree, ends nested swarms first, goes through each
member's own engine (claude stop, moshcode herd kill, tmux kill-pane, a
signal for claude-p) and writes one swarm.end per swarm. tree reads claude
agents --json --all and ~/.moshcode/herd/sessions.json when it can, draws
recordless sessions as roster roots of the implicit fleet, and writes
member.end lost for a recorded member its engine no longer lists.
Claude Code takes part through hooks: logicsrc fleet hooks install merges
SessionStart, UserPromptSubmit, PreToolUse, Stop and SessionEnd into
~/.claude/settings.json without clobbering it, and logicsrc fleet hook
<Event> runs each one. SessionStart claims, derives or writes a root record
and hands the member its variables through CLAUDE_ENV_FILE; UserPromptSubmit
checks the ceiling with the permission mode the engine reports and writes
member.start, or refuses the first prompt with exit 2 and ceiling.refuse;
PreToolUse denies an edit outside piece.owns; Stop and SessionEnd write
member.end. A hand-started root takes the engine's reported approvals
before member.start, since the command line only guesses them. Hooks
never fail the engine: everything is caught and logged to hooks.log.
The spec and the landing page now say what ships, keep Status 0.1, and
record the two verified Claude Code limits: a background job dispatched from
claude agents gets no launcher environment, and OPENFLEET_* exported at
SessionStart reach the member's tools but not later hooks, so hooks key on
session_id through $OPENFLEET_HOME/sessions/<session_id>.json. PRD 0008
covers the work. CLI 0.2.1 -> 0.3.0; build and build:cli chains build the
package before the CLI; README and docs/cli.md list the group.
Tests: 95 in the package (record, ledger merge, every narrower case, the
worked example's claim and derive, the folded tree, hook install
idempotence, each hook handler including the exit-2 refusal and the
PreToolUse deny, every verb with fake deps) and 4 in the CLI.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZV4zJ2pDZLNN3kE5jFCmV
* OpenFleet fix round: rebuild the ceiling from the ledger, once-markers, rule 6 in tree, lost only for what a roster can hold
The review of the reference implementation against moshcode found the two
readers disagreeing on the same files. This round applies the shared
rulings so both sides read a ledger the same way.
Ceiling (R-A, R-B, R-C, R1, R6, R10, R15, R17): memberCeiling rebuilds the
effective ceiling from the ledger on every read. The latest fleet-target
fleet.cap (else fleet.open, else the implicit fleet's) replaces the copy in
a record, so a sysop's widening cap reaches running members; then each
swarm.spawn narrowing down the path, then swarm caps last. In the implicit
fleet a parentless record's own approvals enters at the root; a ceiling a
writer left without the key is never read as native, and startMember fills
it with the engine's word while the record is unclaimed. A fleet.open or
cap with no hosts means the host it was written on (R23).
Once-markers (R-G, R28): member.start, member.end and swarm.end each take
an exclusive create under fleets/<fleet>/marks/<event>.<id> before the
append; a lost end takes <id>.lost so a real end can still supersede it.
The hooks let a real end follow a lost line (R9).
tree (R-F, R20): run by the sysop it enforces rule 6, stopping a member
past its effective until with state timeout and the members of a swarm or
fleet at its budget with state budget, then writes swarm.end for each swarm
touched once it is complete. An agent's tree stops nothing. lost is written
only for a member its engine's roster can hold: a claude-code background job
(8-hex member or session) or a moshcode pane, never an interactive session
claude agents does not list (R-E, R3, R14). A nested swarm is drawn under
the member that spawned it and its row shows the effective ceiling (R25).
stop and cap (R-D, R-H, R22, R27): swarm.end is written only once every
member and every nested swarm has an end line that counts; an engine that
will not end a member leaves it without an end line and the verb exits
non-zero. claude stop takes the job id: the member of a background job,
else the first eight characters of a session UUID; an interactive session
with no job id cannot be stopped and the tool says so. cap on a swarm
refuses a key that would widen. A derived claude-code job is named by its
job id and carries no pid.
Also: R-I (endMember ends only the engine-minted swarm of one), R35 (a
derived record's guessed approvals corrected at UserPromptSubmit), R32
(the UserPromptSubmit hook passes only exit 2 through), R31 (package
README), R36 (rule 13 says the launcher test is unimplemented in 0.1),
docs and PRD 0008 updated for lost, rule 6 and the markers. 113 openfleet
tests, 93 CLI tests, contract green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZV4zJ2pDZLNN3kE5jFCmV
* openfleet hooks: no member.end for a member that never started
A first prompt refused by the ceiling still lets the session wind down through Stop and SessionEnd; those handlers now write nothing when the ledger holds no member.start for the member, so a refused member is never drawn as done.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZV4zJ2pDZLNN3kE5jFCmV
* logicsrc-mcp test: the next free PRD id is 0009 now that PRD 0008 exists
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZV4zJ2pDZLNN3kE5jFCmV
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The footer carries the three OpenWebring links (previous, ring, random,
next, with ?from=https://logicsrc.com/blog, the member URL the directory
holds), and /.well-known/openwebring.json says who makes the blog: both,
ai-generated, in the W3C AI Content Disclosure vocabulary the spec adopts.
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
PR 177 shipped a second OpenFleet under the same slug: a published listing of OpenAgent profiles and ipfile swarms with CoinPay rental offers. Anthony ruled that OpenFleet means the human-controlled fleet and the record of who spawned whom, so the rental contract is renamed OpenRental (slug openrental, catalogs family, group noun listing): docs/openrental.md, logicsrc-openrental.schema.json with type logicsrc.openrental and scope kind listing, fixtures/openrental, createOpenRental and OpenRental* types in the SDK, the openrental validator kind. Minor bumps because an export moved: @logicsrc/schemas 0.2.0, @logicsrc/validators 0.2.0, @logicsrc/sdk 0.2.0. The discovery contract test now covers openfleet, openrental and openwall, one per family, and accepts a landing-page link in llms.txt.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZV4zJ2pDZLNN3kE5jFCmV
One file a ring serves about its members, one file a member may serve
about itself, plain links between them, and a made_by declaration on
every member (human, ai, both) so a reader can follow the human web or
the machine web on purpose. Six hop rules that accept every addressing
shape rings already use (?from=, ?host=, ?via=, ?url=, a slug in the
path, the bare Referer), so a member of any existing ring joins with no
change; verification the IndieWeb way (mark inactive, never delete); an
OPML twin of every ring; no script, no tracking, no central registry.
Name: OpenRing is Drew DeVault's tool in this exact niche and every
openring domain is taken; OpenWebring has only a dead 2020 predecessor
and free domains. Registered in the catalogs family.
First host: rssamplifier.com/ring (one ring per topic), in flight.
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A new spec at /openfleet and /docs/openfleet replacing the AgentSwarm placeholder. A fleet is every agent session one human answers for; a swarm is the members one spawner starts inside it for one task. One record per session (claimed by the first session that writes its member.start, derived when inherited), one append-only ledger per fleet per host with eight events, five sysop verbs, fifteen rules, and what Claude Code and moshcode would each add. Written from job 172ffd83, which had to reconstruct its own parentage by hand.
openswarm keeps its slug (it is the peer-to-peer media family) and gains a one-line pointer. /agent-swarm redirects permanently to /openfleet; the registry entry, home band, catch-all route and scroll hook for the placeholder are replaced or removed. Contract test covers the redirect.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZV4zJ2pDZLNN3kE5jFCmV
* feat: add OpenFleet membership and CoinPay rental contracts
* Propose OpenWall broadcasts and direct messaging contracts
* release: prepare OpenFleet and OpenWall public contracts
* fix: use tested npm for compatible CLI installs
Every consumer of a link reads a page's card tags its own way, caches the
first reading for days, and publishes nothing. OpenSite writes the reading
down: a record per URL (title, description, image, kind, canonical, author,
feeds, the card tags verbatim, JSON-LD as parsed), a descriptor a site
serves at /.well-known/opensite.json, the order a reader takes each field
from a page, the four calls an index offers, and a table of what each
consumer reads and caches.
docs/opensite.md, one entry in the specs registry (catalogs family), and a
landing page at /opensite. The first index is nichedb.dev/c/sites; the
first publisher is nixamp's share links.
Claude-Session: https://claude.ai/code/session_01MwAoNvWzezmBHeT7oDHo3C
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Subscribing takes one click and cancelling takes a support ticket, and no
reader can check that the two are as easy as each other because the way
out is not written down anywhere a reader can fetch. The service already
has a plan table, a cancel endpoint and a refund rule. OpenSaaS is those
at /.well-known/opensaas.json: plans, and eight actions (subscribe,
cancel, pause, resume, change_plan, unsubscribe, export, delete), each
as the page a person opens and the endpoint an agent calls with an
OpenAccess scope, with steps and confirm as the exit measure a directory
shows beside the entrance. Doc, landing page, registry entry under
catalogs. nichedb.dev is named as the first directory and the first
service.
Claude-Session: https://claude.ai/code/session_01S7yeJUHGxA4P5N74xnsRPQ
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The SimpleFIN door written down for anything a bridge holds: a person gets
a single-use setup token from the bridge, pastes it into an app, the app
claims it once for an access URL and a bearer the bridge can revoke. No
client registration, no redirect, no key for the app to keep, which is what
a browser extension or a script needs. Bearer instead of SimpleFIN's Basic
credentials in the URL, because a browser's fetch refuses those. Eight
rules, the social profile (accounts, analyze, write, suggest, activity,
posts only when declared) and the finance profile (SimpleFIN, unchanged).
First bridge: mynaposter.com (/connect). First app: DefPromo. Registered
as one entry in the specs registry under Access and credentials, beside
OpenAccess, which is the registered door with the same scope vocabulary.
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A publisher and a disk each say which CLI drives them, in the same
`developer` shape OpenServer 0.2 defines, so a marketplace shows one
install line beside every listing without reading a docs page per host.
fi1zes.com is the name chosen for the OpenFile marketplace on 2026-09-13,
not yet registered; bittorrented.com stays the reference reader until then.
Claude-Session: https://claude.ai/code/session_01Khk1C6Ese6xjdHAWLVstca
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
How a machine should sound when it speaks for you, and the order a reader
chooses in: Voice, then Gender, then Pronouns, never a name or a photo.
Gender means the same in the identity block and under Match. The first
reader is nixamp's party line, which reads trollbox lines to the people
on the phone in a room in the author's voice (nixamp 0.23.5).
Claude-Session: https://claude.ai/code/session_01GxYGCCvvuhVAkU1W2iJKTV
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A directory that lists a host's plans is asked the next question at once:
how do I drive this thing from a terminal? Every provider answers it on a
page of its own, in its own words, and a reader that wants the install line
has to find and read that page for each host. nichedb.dev's hosting
collection just did exactly that for 46 providers, copying the commands
off each vendor's guide, and the exercise is the argument for putting the
facts in the descriptor.
`provider.developer` names the official CLI, its install commands keyed by
package manager and copied as the guide prints them, the install guide and
source, the API docs, the Terraform provider and the GitHub organisation. A
provider with no CLI says `"cli": null`, which is a fact, while a missing
block means unknown. Commands are copied, never composed: a reader that
invents `brew install <name>` sends a buyer to a formula that may not exist.
c0mpute.md gains the same block for the compute market, with the one
install line c0mpute.com prints, and the landing page says what 0.2 adds.
Claude-Session: https://claude.ai/code/session_01Khk1C6Ese6xjdHAWLVstca
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Anthony: "this needs a cookie crumb navbar, all pages need this with the
new IA" and "broad and drill down, I'm not seeing that in the sidebar".
lib/crumbs.ts derives the trail from the path and the spec registry, so
no page declares it: /openthreat is Home > Specs > Catalogs a site serves
about itself > OpenThreat, /opencpu adds OpenServer before OpenCPU,
/docs/openthreat ends in Specification, /docs/cli is Home > Docs > CLI,
a blog post passes its title as the leaf. components/breadcrumbs.tsx
renders it (server-rendered, with a BreadcrumbList JSON-LD) at the top
of every SiteShell page; the SPA routes rendered by page-markup.ts get
the same trail as a string.
components/side-nav.tsx replaces the flat sidebar: the four groups stay,
and under Specs the family the current page belongs to unfolds to its
specs, and the spec to its blocks, marked active. The home page string
marks the active entry for the SPA routes too.
Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Anthony: "that site needs better information architecture, it's impossible
to find anything", "start broad in sidebar and drill down with dedicated
pages, not all one page", and "I see none of our specs" on the home page.
One registry, lib/specs.ts, now lists every specification in four
families (people and agents; access and credentials; catalogs a site
serves about itself; agents and process), with a landing path, a
specification path and, for OpenServer's blocks, a parent. Everything
that lists specs reads it: the sidebar (lib/nav.ts, four groups: Start,
Specs, Tools, Company, rendered by SiteShell and by the home page string
from the same array), /specs and /specs/<family>, the home page's
Standards Surface grid (families with their specs, replacing the five
abstract primitives), /docs (grouped by family, then guides), the sitemap
and llms.txt. DOC_SLUGS is derived from the registry. Adding a spec is
one entry plus its files; the four hand-kept lists are gone.
Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* docs: OpenBroadcast and OpenGuest, the broadcaster-and-guest framework as OpenProfile.md sections
Anthony: "broadcasters and guests is the usual framework for live audio
shows, radio, podcasts" and OpenProfile.md should carry it so a platform
(anyfans) can match hosts with guests from two files rather than two
forms. OpenExpert folds into OpenGuest: an expert is a guest with
Expertise and Credentials.
OpenBroadcast is the `## Broadcast` section: Show, Kind, Format, Live,
Cadence, Length, Language, Audience (host's own unit), Feed, Topics,
Seeking, Not, Slots, Remote, Book, and Pays / Charges (unstated by
default, because pay-to-play is the thing a guest is most often not
told). OpenGuest is the `## Guest` section: Available, Expertise,
Credentials, Pitch, Formats, Live, Languages, Availability, Lead time,
Remote, Rate, Pays, Appeared on, Press, Book, Not. Matching scores
Topics/Seeking against Expertise/Topics, Slots against Availability,
Pays/Charges against Rate/Pays; both Not keys are absolute; a platform
never fills a key the person did not write. Both landing pages share
profile-section-page.tsx. OpenProfile.md names the two sections in rule
4 and in Related standards. Registered in the four places.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ
* ci: trigger workflows
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>