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>
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
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>
* docs: OpenThreat, one file a security tool serves about what it found in the open
Twelve rules that degrade and two that do not: a subject is public or it
is not in the file (no private repos, no customer servers, no paid users'
scans), and a secret is never located while it is open (rule, severity,
subject, status only; no location, message or excerpt). Four kinds:
finding, attack, indicator, advisory. Status open, fixed, mitigated,
blocked, withdrawn; a withdrawn threat stays a while so directories
retract it. Announcing is on by default with a one-switch opt-out in the
tool's own settings. Discovery at /.well-known/openthreat.json,
rel="openthreat", or a handed URL; origin is the verification. Mapped
against SARIF, STIX 2.1 and CSAF rather than replacing them.
First reporter: threatcrush.com/discovery (its own PR). First directory:
nichedb.dev/c/threats (its own PR). Registered in DOC_SLUGS, NAV,
STATIC_ROUTES and llms.txt.
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>
The descriptor at /.well-known/openaffiliate.json (programs with pays,
link, window, attribution, hold_days, payout, approval, self), the four
calls (join with an OpenProfile.md, link with ?oa=code, read the ledger,
get paid to your own address), webhooks, discovery, what a directory
owes a merchant, and what is deliberately absent: no network in the
money, no tracking host, no application form, no exclusivity, no
impression payments. Landing page at /openaffiliate, registered in
DOC_SLUGS, NAV, sitemap and llms.txt. Reference implementation is
crawlproof.com/affiliate.
Claude-Session: https://claude.ai/code/session_01CDEiDss9RWYibtmxSk5Gr2
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Anthony: every top-level nichedb.dev niche may need its own open<niche>
spec so the serve-your-own-file pattern scales across industries. These
are the two he named first.
OpenCoupon: one JSON file a merchant serves at
/.well-known/opencoupon.json about what is on offer right now: every
code, sale and shipping threshold with kind (percent, amount, shipping,
bogo, gift, other), value, scope, min_order, dates, status, per-customer
and region limits. Expired coupons stay in the file so a directory
learns a code died from the one party that knows. No affiliate links,
no redemption, no votes. First reader: nichedb.dev/c/deals.
OpenRecipe.md: one Markdown file that is a recipe, in the OpenProfile.md
and OpenResume.md style: a summary block (Serves, Prep, Cook, Cuisine,
Course, Diet, Author, Source, Image), a description line, Ingredients
and Steps as written, Notes, Nutrition per serving. Served next to the
page, linked with rel="openrecipe", or indexed at
/.well-known/openrecipe.md. A one-way mapping to schema.org/Recipe:
the JSON-LD is generated from the Markdown, never the reverse.
Both registered in DOC_SLUGS, NAV, STATIC_ROUTES and llms.txt.
Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
OpenSwarm says how a file lives on a swarm and how a seeder is paid to hold
it, and nothing in it gives a person with a browser, a search engine or a
directory a URL to start from. A manifest is on the DHT under a key, the
catalogue is a feed found through the DHT, the seed market is one-sided:
offers are listed and seeders poll them. A requester who wants a box in
Germany with two terabytes free and a year of clean proofs has no file to
read, and a seeder with those things has no file to serve.
OpenFile is /.well-known/openfile.json on a publisher's origin: each file
by its plaintext content hash (the ipfile plainRoot, so the id a reader
gets is the root the decrypted file verifies against), every way to fetch
it (an ipfile magnet, a webseed, plain HTTP by range, HLS for a player
with nothing installed), the pay2seed attestation and README, the price
as an x402 offer URL, and a holders list of who has the bytes now with
the age of each seeder's last proof. Encryption is ipfile unless the
publisher says none as an explicit act.
OpenDisk is /.well-known/opendisk.json on a machine that rents disk: free
GiB, price per GiB-month in the unit pay2seed already prices in, the
operator's accept policy stated up front so nobody posts an offer the disk
would never take, proof cadence, the seeder key and the hubs it takes
leases at, and a record block whose source is the hub's own seeder page,
because a marketplace reads standing from the hub and never from the
file. d1sks.com is the reference marketplace. A disk is also an OpenServer
offer of kind storage, and the mapping is a table, so the nichedb hosting
collection lists every disk without a second parser.
Neither restates a record that already has a name: the swarm is ipfile,
the consent is pay2seed, the leases and proofs are paid2seed, the payee
and the pass are ippay, the feed is ipdb. Both are registered in the four
places a LogicSRC spec needs and added to the OpenSwarm family table.
OpenFile has no product domain yet and says so.
Claude-Session: https://claude.ai/code/session_01Khk1C6Ese6xjdHAWLVstca
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Four resource specifications under OpenServer, one per thing that is
negotiable when a server is bought. Each is the block of an OpenServer
offer (compute, memory, gpu, network) written down on its own, with the
units OpenServer 0.1 already uses (vcpu, cores, ram_mb, vram_mb,
bandwidth_mbps, transfer_gb, ipv4, ipv6) and one new shape shared by all
four: `range`, the field a buyer can dial at checkout, its bounds, the
step and what a step costs on top of the base price.
- OpenCPU: threads against cores, the processor by its vendor name,
dedicated, shared or burstable allocation.
- OpenMemory: mebibytes, DDR generation, ECC as three states, reserved,
balloonable or shared; wins over compute.ram_mb when both are present.
- OpenGPU: the card by its vendor name, count and VRAM per device,
interconnect, passthrough, MIG, vGPU or shared access.
- OpenBandwidth: port, four meters (transfer, unmetered, percentile,
flat), overage, IPv4 and IPv6 addresses as a priced resource.
A provider that sells only one resource lists it as an OpenServer offer
and may serve the same document at /.well-known/<slug>.json. Landing
pages share one component (resource-spec-page.tsx). Registered in
DOC_SLUGS, NAV, STATIC_ROUTES and llms.txt. OpenServer, OpenFile and
OpenDisk arrive in sibling PRs.
Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* OpenServer 0.1: one file a hosting provider serves about what it sells
A new LogicSRC spec at /openserver and /docs/openserver. A provider puts
the table its order form already reads at /.well-known/openserver.json:
every offer with a kind, four axes, specs in fixed units, one price,
location and stock. A directory reads the provider instead of scraping
an aggregator whose terms forbid it, and the provider stays the author
of its own catalog. Only provider.name and each offer's name are
required; every other rule degrades.
Fifteen kinds cover what Anthony listed and the rest of the market:
cloud, vps, dedicated, bare-metal, colocation, on-prem, shared, managed,
paas, serverless, storage, gpu, edge, p2p and hybrid. Premises,
management, tenancy and model are their own keys rather than inferred
from the kind, because a managed VPS and an unmanaged one are the same
kind and different offers. A peer-to-peer market publishes one
descriptor whose offers are its current asks, with the operator pointing
at the market and not the peer; c0mpute is the compute case, OpenDisk
the storage case, OpenSwarm the settlement layer under both.
The first reader is nichedb.dev's hosting collection, being built
alongside this. findhost.app is named as the curated sibling.
Registered in DOC_SLUGS, NAV, STATIC_ROUTES and llms.txt, one line each.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Khk1C6Ese6xjdHAWLVstca
* OpenServer: name the resource blocks an offer may carry
OpenCPU, OpenMemory, OpenGPU and OpenBandwidth are being written as the
blocks that nest inside an offer's compute, compute.gpu and network, and
that stand alone as offers. Related standards now says so, with links at
/docs/<slug> where those specs will land. No subdomain is named anywhere
in this spec: every LogicSRC spec lives on logicsrc.com only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Khk1C6Ese6xjdHAWLVstca
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A new LogicSRC spec at /openaccess and /docs/openaccess. A person, an
agent or an organisation keeps one account at a hub; every app keeps its
own users and links each to that account once. Grants delegate narrower
to agents, and a subscription bought in one app is honoured by every app
that honours the product. The app descriptor, the hub metadata, the four
flows, the token, signed webhooks and the hub's own doors.
Registered in DOC_SLUGS, NAV, STATIC_ROUTES and llms.txt.
Reference implementation: github.com/logicsrc/openaccess, hub at
openaccess.logicsrc.com.
Claude-Session: https://claude.ai/code/session_01SWRffW4ifQPUrGXJtgYWMd
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A relay serves /.well-known/openmcp.json; a catalog probes it (the
descriptor from the relay's own origin, then initialize and tools/list)
and lists only what it found; a client reaches every relay through the
catalog's REST, its own MCP endpoint, or signed webhooks. Landing page at
/openmcp, the document at /docs/openmcp, registered in the same four
places as the other specs. Reference implementation at
github.com/logicsrc/openmcp.
Claude-Session: https://claude.ai/code/session_01FMT2v1YxmgcDuionrfT719
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A new LogicSRC spec at /openprofile with the document at /docs/openprofile.
Eight degrading rules (name, identity block, headline, sections, accounts,
topics, reshare terms, operator), three discovery locations
(/.well-known/openprofile.md, rel="openprofile", a platform path) and
verification by linking back. Registered in DOC_SLUGS, NAV, STATIC_ROUTES
and llms.txt, the same four places as ASDLC.
myna writes one from its accounts and publishes the Reshare section to the
myna reshare network; agenticjobs serves one per public candidate.
Claude-Session: https://claude.ai/code/session_01FMT2v1YxmgcDuionrfT719
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
ASDLC 0.1 describes how software gets built when most of the work is done
by agents running in parallel and CI/CD is the only gate. It is a
description of a practice already in production, not a proposal.
The traditional SDLC assumes the scarce resource is engineering time, so
it spends process on deciding whether each change is worth building. When
agents write the code, engineering time stops being scarce and two other
things become scarce: human attention, and trunk stability.
Nine phases: frame, fan out, gate locally, merge, release, verify live,
correct, ratchet, promote. Correct returns to fan out, so the loop is the
lifecycle.
The load-bearing phase is the ratchet. Testing in production is only
defensible if production failures are one-time events, so every escape
becomes a permanent automated check before the incident is closed, and
that check has to be confirmed to fail when the bug is reintroduced. A fix
without a ratchet is how the same class of bug ships three times.
Four conformance levels, of which only level 3 requires evidence rather
than intent. The worked example is DiskPush on 2026-09-06: eight agent
worktrees on one checkout, four releases between 08:53 and 14:56 UTC, and
a three-release desktop bug whose first layer no local harness could have
caught, because a static server resolves absolute paths correctly by
construction and the bug only existed under file://.
Published at /asdlc with the spec at /docs/asdlc, listed in the nav,
sitemap and llms.txt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Q2bt449mEJSHoEZzaemCn
BitTorrent distributes bytes better than any CDN and has never been a
product: nobody is paid to seed, and nothing in it is private. Every
Profullstack media property answers that with a central HTTP proxy and a
pass system bolted on, and pays for every byte it serves.
OpenSwarm is an add-on to BitTorrent, carried as BEP 10 extension
messages, that fixes both. The swarm carries AES-256-CTR ciphertext whose
integrity is pinned by two SHA-256 merkle roots in a signed manifest, so
a tracker or DHT node learns an infohash and a size. A leecher buys a
pass over x402 in USDC (the same exchange x402-gateway runs for crawl
passes, settled by CoinPay), a seeder serves inside a bounded credit
window, and the leecher signs a cumulative voucher for every verified
batch. Whoever seeds gets paid. Vanilla clients remain valid members and
browsers remain first-class peers.
Adding a file mints a key pair for it, derived from one publisher seed by
default so there is one thing to back up: the public half is the file's
identity and its BEP 46 key, the private half signs the manifest and
authorises grants and payout changes, and a separate content key
encrypts the bytes and is sealed to paying peers.
The family: a core (records, keys, hashing, transports, discovery,
events), ipfile, ippay, ipdb (a signed hash-chained catalogue with heads
on the DHT), ipaudio, ipvideo, iplive (paid relays with backpressure)
and ipname (Moshpit pins and DNS TXT). Plus the c0mpute.com integration
with seven workload types and thirteen use cases, a proposed ip CLI,
conformance profiles, a security model and an FAQ.
Registered on the site the way OpenCreds is: nav entry, docs registry,
sitemap, a /openswarm landing page, PRD 0005, and the MCP prd_next_id
expectation moved to 0006.
Specs only. No code, no schemas, no reference implementation.
Claude-Session: https://claude.ai/code/session_01YafYxayh7Gqe5MWNNQMev2
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* Add the LogicSRC OpenCreds specification
Leaving a password manager means writing every secret you own to disk in
the clear, and losing whatever the spreadsheet had no column for. A CSV
is plaintext by construction, lossy by omission, and carries no
integrity: nothing in it says which rows were meant to be there, so a
truncated import looks exactly like a complete one.
The same gap showed up inside LogicSRC. `logicsrc credentials` moves
.env secrets and SSH keys through end-to-end-encrypted team vaults, but
it can only model a key/value pair. A card, a passport, a login with a
TOTP seed, or an OAuth account with a refresh token are all things
people already keep in a vault, and none of them are a key/value pair.
OpenCreds defines three things: the item, the vault, and the database.
- Six item types (login, card, identity, note, key, account) as one
record with a type and a named field group, so everything the user
typed lives in a single encrypted blob. Codes 1-4 match MarkSyncr's
deployed vault and are not renumbered; compatibility is cheaper than
elegance.
- AES-256-GCM over that record with the item id bound as AAD. Without
it, anyone with storage write access could move a low-value login's
ciphertext into a high-value row and watch what the user does next.
- A key hierarchy where the user key is random, not derived, so a
password change re-wraps 32 bytes rather than re-encrypting a vault.
The auth hash comes out of a different HKDF label than the wrap key,
which is what lets it reach a server at all.
- A portable .opencreds file, encrypted by default, whose header is the
AAD over the payload -- so the manifest is authenticated by the same
tag as the data and a truncated import fails rather than reporting
success. The plaintext form exists because people move to products
that read nothing else; it is opt-in, confirmed, 0600, and labelled
"protected": false in its own header.
Namespaces are carried as data, not fixed by the spec: labels are
compiled into every ciphertext a vault has written, so editing one does
not migrate a vault, it makes it undecryptable. MarkSyncr's deployed
vault is conformant by declaring `marksyncr`.
Ships: prd/0004, nine spec pages under docs/opencreds/, six JSON
Schemas, the @logicsrc/opencreds reference implementation with CSV
importers for five products, `logicsrc vault` and the standalone
`opencreds` binary, and the spec page at logicsrc.com/opencreds.
`vault` rather than `creds` because `creds` is already an alias of
`logicsrc credentials`, and the two are different: one moves a pair
between providers, the other stores a record.
@logicsrc/validators now registers every schema by $id before
compiling, so the database schema can $ref the item and manifest
schemas rather than restating them.
120 tests, including CLI end-to-end coverage of the masking rules,
exit codes, and the manifest-mismatch path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QRQrfuwuYKKV5UB9kLHuX5
* Make the OpenCreds conformance claim executable
The conformance page described a fixture suite and an `opencreds
conformance` command that did not exist. A specification that documents
a conformance surface it cannot run is a specification nobody can hold
to, including us.
`opencreds conformance` now runs the requirement list as code -- one
check per C-number, carrying its own id and level -- and emits the
report shape the spec publishes. It exits 2 when a MUST does not pass,
so it can gate CI directly. The reference implementation reports 29
passed, 0 failed, 1 skipped; the skip is C19, because key management for
the team profile lives in @logicsrc/plugin-credential-sharing rather
than in this package, and a skipped MAY does not affect conformance.
Fixtures are generated (`--emit-fixtures <dir>`) rather than
hand-written. A vector produced by an implementation and then verified
by it is worth more than a JSON file someone typed: the typed file
drifts silently when the format moves, and the generated one cannot.
Fourteen files, including an invalid/ set every conforming reader must
reject -- a wrong field group, a weak KDF, an unregistered namespace, a
short payload and a tampered manifest.
The CLI requirements stay with the end-to-end tests that drive the real
binary through a child process; a command cannot meaningfully check its
own exit codes, and a masked value that is only masked in the library is
not masked.
conformance.md and cli.md now describe what ships.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QRQrfuwuYKKV5UB9kLHuX5
* Add @logicsrc/opencreds to the lockfile
`npm ci` refuses a lockfile that does not match package.json, and the
new workspace package plus the CLI's dependency on it were never
recorded: the worktree was bootstrapped by hardlinking node_modules
rather than installing, so npm was never asked to update the lock.
Adds the workspace link and the package entry. No dependency versions
move.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QRQrfuwuYKKV5UB9kLHuX5
* Register PRD 0004, and stop the fixtures looking like real secrets
Two CI failures, both mine.
`prd/README.md` is generated by `logicsrc prd index --write` and the
scaffold test asserts it is current, so adding a PRD without
regenerating it leaves the repo's own conformance check failing.
Regenerated. The MCP test asserts the next free PRD id against the live
prd/ directory — its comment says it advances with every PRD added — so
it moves to 0005.
ThreatCrush flagged three of the example strings: a PEM header in the
item-model docs and in the conformance fixture, and an `sk_live_`
prefixed token. All placeholders, none real, but the finding is the
scanner working. A fixture only has to exercise the field, and a
real-looking private key header or live-key prefix sitting in the tree
trains both the scanner and the people reading its output to shrug at
exactly the shape that matters. Replaced with obvious placeholders
rather than suppressing the rule.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QRQrfuwuYKKV5UB9kLHuX5
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The "Top-Level Pages" band advertises eight stable routes, but the cards
were plain <h3> text with no anchors -- nothing on that band was
clickable. Wrap each card title in a link to its route.
/privacy was the worst of the eight. It had no page and no homepage
section, so it fell through to [[...slug]], which served the entire
homepage (82KB, byte-identical to /openspec, /credential-sharing, and
/hire-us) and then scrolled to the card that merely described the page
that did not exist. Give it a real page covering what the site actually
does: CrawlProof analytics, the Hire Us form, the CoinPay OAuth session
cookie, and the credshare boundary -- ciphertext and salted-hash
fingerprints are stored, secret values never reach the server.
The cards also reused the ids openspec, credential-sharing, and hire-us,
which already name sections further up the same document. Duplicate ids
made those scroll targets ambiguous, so the cards are now page-<route>.
With that, the scroll list in home-interactivity only needs the three
routes [[...slug]] still serves; docs, blog, about, terms, and privacy
are real routes and were only ever aiming scrollIntoView at a card.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The CLI is the product, and the way you get it was nowhere on the site. You
had to already know the URL of a script served out of public/.
Two placements, one command:
- The homepage hero gets the loud version, directly under the lede and above
the fold -- a bordered dark panel, the command at full size, Copy alongside.
- Every page carries a compact version in the rail, between the brand and the
nav. Present on arrival, never competing with navigation.
Both come from renderInstallCommand() in one module. The homepage builds its
HTML as a string and the rest of the site is JSX, which is precisely the shape
that lets one copy of a command drift while the other stays right -- so there
is one definition and SiteShell renders it rather than restating it.
The command keeps its flags: `curl -fsSL`. Without -f, curl prints an HTTP
error body and still exits 0, so a 404 gets piped into sh; without -L the
install breaks the first time the URL redirects. This is the form install.sh
already documents in its own header.
Copy is one delegated listener on document for any [data-copy] button, mounted
site-wide in the layout. Delegation because the two placements arrive by
different rendering paths and a document listener does not care which; it also
means the next copy button needs the attribute and no wiring. It falls back to
a throwaway textarea + execCommand outside a secure context, where
navigator.clipboard is simply undefined, so the button never no-ops silently.
The contract tests pin the command, both placements, and that the clipboard
payload equals the visible text -- a Copy button that hands over something
other than what is on screen is worse than no button. They also read
public/install.sh and assert it is #!/bin/sh and documents this exact command,
so `| sh` cannot quietly become a lie.
apps/logicsrc-web: 13 new tests pass, 46 total. The ontology-api contract file
fails to resolve @logicsrc/validators, which it also does on a pristine
origin/master -- unbuilt workspace package, unrelated to this change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(web): move Hire Us pricing to $400/hour metered billing (PRD 0002)
Replaces the $250/week retainer with a $400/hour rate billed against actual
hours, invoiced through CoinPay after the client approves them. A 10-hour
minimum engagement replaces the week as the unit of commitment.
The weekly price lived in 12 places, not the 3 the PRD listed: the front-page
Hire Us section, the Top-Level Pages list, /hire-us metadata, /pricing
(metadata, two FAQ answers, rate bullet), /about, llms.txt, skill.md, and the
Hire Us form success message.
Metered billing rather than a committed weekly block, because the old
"recurring CoinPay invoice" copy documented a mechanic that never existed:
/api/payments/create makes a single one-shot payment, not a subscription.
- coinpay-checkout derives amount_usd from hours x 400 instead of a hardcoded
250, validates hours as quarter-hour increments at or above the minimum, and
returns 422 before calling CoinPay on bad input. Payment metadata carries
billing/hours/rate_usd_per_hour in place of interval.
- project-request returns a rate, billing mode, and minimum; no amount exists
until hours are approved.
- CoinPay config block documents COINPAY_RATE_USD_PER_HOUR / COINPAY_BILLING /
COINPAY_MINIMUM_HOURS instead of a weekly amount and interval.
- New real /terms route replacing the SPA stub: what is billable, the
approve-then-invoice flow, the minimum, cancellation on one week's notice,
and an explicit clause that existing engagements keep their terms until both
sides agree in writing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(mcp): advance prd_next_id expectation to 0003 for PRD 0002
The standards test asserts prd_next_id against the live prd/ directory, so
adding prd/0002-hourly-hire-us-rate.md moves the next free id to 0003. This
assertion advances with every PRD added to the repo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Everything the two shipped PRD phases deferred, minus what is called out below.
Storage (Phase 2)
@logicsrc/openontology gains a SQLite/Turso adapter. It hydrates the read
model at open, serves reads synchronously — a query evaluator that awaits per
triple pattern is unusable — and buffers mutations as SQL that flush() writes
in one transaction. Versioned idempotent migrations; indexes over subject,
predicate, entity-valued object, status, both time axes, aliases, and external
ids; FTS5 for label/alias search. The append-only status log is replayed on
open, so retractions, supersessions, and merge redirects survive a reopen.
REST + SSE + OpenAPI (Phase 2)
16 paths under /api/ontologies in logicsrc-web, described at
/api/ontologies/openapi and referencing the published JSON Schemas rather
than restating them. No token is read-only; a curator token can apply; an
agent token can propose and cannot apply. Idempotency-Key on mutations,
revision ETags, 409 on a stale base revision, and an SSE stream that emits
the same event objects as the JSON endpoint.
MCP (Phase 2)
OpenOntology and OpenPRD surfaces on the standards server: spec/manifest/
schema/queries and PRD spec/index as resources, 11 ontology tools and 6 PRD
tools, 7 prompts. Read-only by default; OPENONTOLOGY_MCP_WRITABLE=1 buys
proposals, never applies — the denial is the shared policy layer, not a
second rule that could drift.
Interoperability (Phase 3)
RDF/Turtle export and import of the reified profile, plus the plain triple
for asserted relationships so a consumer wanting only the accepted graph gets
one. SHACL for 5 of 7 constraint kinds; `unique` and `query` are reported as
unmapped in both the return value and the generated Turtle, because a shape
that quietly means something narrower is worse than no shape.
Source adapters (Phase 3)
CSV, JSON, YAML, NDJSON, Markdown, generic JSON HTTP, and GitHub. All produce
PROPOSED change-set operations with source, evidence selector, run id, and
confidence attached; fetch is injected so ingestion is offline and testable.
Each declares its capabilities, so "nothing was deleted upstream" is never
confused with "this adapter cannot see deletions" — none of the seven can.
TUI + explorer
Keyboard-first panels (types, entities, claims, sources, queries, change
sets, validation, audit) as plain strings that survive SSH and 60 columns;
status is a glyph and a word, never colour alone; the key bar wraps rather
than truncating. Wired as `logicsrc ontology tui`. A read-only web explorer
at /openontology/explore with entity and claim views showing status, both
clocks, confidence, sources, evidence, and append-only history — plus an
/openprd page for the companion standard.
Bugs found and fixed while testing
- the API built a new engine per request, so `explain` could never find a
resultId from a prior request; engines are now cached per role
- the TUI status bar called engine.validateOntologyPackage(), appending a
package.validated event on every repaint; it now uses the pure validator
Verification: 76 new tests (527 total across the monorepo, all passing); full
build green; the libSQL adapter is exercised against real files, the API
through its route handlers, and MCP over an in-memory transport.
Not included: PWA review/approval write flows (they need an auth story this
deployment does not have), OWL/RDFS mappings, SPARQL/Cypher/Datalog query
adapters, and Phase 4 governed actions. The compatibility matrix marks those
"planned", not "supported".
Refs: prd/0001-add-logicsrc-openontology-spec.md
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
OpenPRD has existed as a document (docs/openprd.md), a front-matter schema, a
template, and this repo's prd/ collection. Nothing enforced it. This adds the
reference implementation.
@logicsrc/openprd
- parser: front-matter + the eight `##` sections + numbered requirements.
`###` stays content so a long Requirements section can be organized, and
headings or R#-shaped lines inside code fences are ignored
- validation splits the standard's four conformance rules (filename,
front-matter schema, id-matches-prefix, eight sections in order) from
lint (empty section, missing priority tag, numbering gaps, duplicate R#,
date order, one-sided supersession, stale index). Conformance failures are
errors; --strict promotes the rest. Stable codes, file, line, hint
- collection rules the per-file view cannot see: unique ids, monotonic
numbering with no gaps, 0000 reserved for the template, cross-references
that resolve
- lifecycle enforced rather than advisory: Draft cannot jump to Final,
terminal statuses do not resume, Superseded must name its replacement
- deterministic index generation, so `prd index` is idempotent and CI can
diff it
- front-matter rewriting that leaves the body byte-identical
- the optional LogicSRC task bridge the standard describes: each R# becomes
one logicsrc.task, validated against logicsrc-task.schema.json before it
is emitted; creator DID derived from the author email
CLI: logicsrc prd init|new|list|show|validate|lint|index|status|next|tasks|
export. Exit codes stable for CI (0 ok, 1 invalid, 2 usage, 3 not found).
Conformance bundle: packages/schemas/fixtures/openprd/ — 6 documents that must
validate and 12 that must fail, each naming the error code it must produce.
Several rules depend on the filename, so every fixture records the name it is
validated as.
Docs: an Implementation section in docs/openprd.md (CLI, validation model,
task bridge, conformance bundle), the spec added to the site's docs surface,
nav and sitemap entries, and a README section.
Verification: 76 new tests; full monorepo build and all 451 workspace tests
pass. The suite dogfoods this repo — prd/ validates with zero errors and zero
warnings, the embedded template is byte-identical to docs/openprd/0000-
template.md, and all 210 requirements in PRD 0001 map to schema-valid tasks.
prd/README.md is regenerated by the tool it now ships.
Refs: docs/openprd.md
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Implements OpenPRD 0001 through Phase 0 (specification, schemas, example,
docs surface) and Phase 1 (local engine, CLI, conformance tests).
Schemas (17 contracts, JSON Schema Draft 2020-12, additionalProperties:false)
manifest, namespace, entity-type, property, relationship-type, constraint,
query, action, entity, claim, source, evidence, changeset, review, approval,
event, package — registered in @logicsrc/validators and exported from
@logicsrc/schemas under https://logicsrc.com/schemas/openontology/.
@logicsrc/openontology
- canonical JSON + sha256 package digests; YAML, JSON, NDJSON, and inline
authoring all compile to the same bytes, so digests are authoring-agnostic
- id profile: compact / IRI / urn with one canonicalization rule, prefix
bound by a Namespace object so IRIs reverse unambiguously
- validation: schema, graph (domain/range, datatypes, dangling refs),
provenance (source-or-firstParty, agent runId, derivation inputs), policy
(excerpt limits, licensing, visibility, staleness) and declared
constraints; four severities, stable codes, text/json/yaml/markdown
- portable triple-pattern query AST: multi-hop, 14 operators, asOf and
recordedAsOf, per-status filtering, distinct/order/limit, explanation
mode, and enforced depth/binding/row limits
- append-only store: claims are immutable; dispute/retract/supersede append
status transitions and the effective status is the latest one
- change sets: 9 operations, atomic pre-flight, conflict detection on stale
base revisions, semantic diff with duplicate-identity warnings and
affected-query deltas, per-operation reviewer decisions
- policy: agents propose but can never apply — the denial keys on actor
type, so every scope plus high confidence plus --yolo still cannot apply;
merges need approval, bulk retractions need two, undeclared action side
effects are denied
- JSON-LD 1.1 export/import with PROV-O aliases and lossy-field reporting
- pluggable signature envelope with a jws-ed25519 reference profile and a
fail-closed trust policy
CLI: logicsrc ontology init|validate|lint|build|inspect, entity, claim, query,
changeset, import, export, audit. Reads take --format, writes default to a
proposal, exit codes are stable for CI.
Example: examples/openontology/ethereum-ecosystem — 12 entity types, 17
relationship types, 63 entities, 169 claims, 25 sources, 31 evidence records,
5 saved queries, every claim lifecycle state, and a pending merge proposal.
All data is fictional; the directory is removable without affecting any core
test.
Docs: docs/openontology{,-governance,-interoperability}.md, a real
/openontology route, homepage + nav + sitemap entries, and a root README
section.
Verification: 112 new tests; full monorepo build and every workspace test
pass; conformance bundle (18 valid + 13 invalid fixtures) runs against the
published schemas alone; Node.js 25 and Bun 1.3 produce byte-identical
digests, revisions, event trails, and query results.
Not included (later PRD phases): MCP resources, REST/SSE, Turso adapter, TUI
and PWA surfaces, RDF/SHACL mappings, source adapters, governed actions.
Refs: prd/0001-add-logicsrc-openontology-spec.md
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds apps/pwa: an Express + libSQL/Turso app that is now the home of team
credential sharing, with the moshcode-style auth stack ported and reskinned to
match logicsrc.com (light theme, Inter, green accent).
apps/pwa
- auth: email/password (scrypt), passkeys (WebAuthn), CoinPay OAuth, cookie
sessions, and lsk_ API keys for the CLI via a loopback OAuth-PKCE flow
(/cli/authorize + /cli/token). Ported from the moshcode PWA.
- credshare API (/api/credshare/*): teams, members, invites, vaults, sealed
grants, ciphertext secrets, audit — authed by session OR Bearer lsk_ key.
Zero-knowledge: only ciphertext + sealed vault keys + public keys stored.
- teams dashboard, accept-invite, and settings (API keys) pages, server-rendered
in the LogicSRC brand (lib/html.mjs).
- migrations (libSQL) 001_auth + 002_credshare, migrate-on-boot; Turso via
TURSO_DATABASE_URL / TURSO_AUTH_TOKEN, or a local file db for dev.
- trimmed moshcode-specific approvals/credits/push/deliver.
CLI
- `logicsrc login` now does browser loopback OAuth-PKCE against the app and
stores an lsk_ token (email-OTP removed); --token for CI. Client repointed.
Distribution
- install.sh (served at logicsrc.com/install.sh) installs the CLI from the
GitHub repo: tarball -> npm install -> `npm run build:cli` -> logicsrc wrapper.
- root build:cli builds only the CLI's workspace chain (skips web/api/next).
Cleanup
- removed the commandboard-api credshare backend (superseded by the PWA) and its
Supabase/Turso stores + libsql dep; commandboard-api tests green (40).
- removed the Next.js /teams page (the PWA is the web UI now).
Verified end-to-end: two accounts register on the PWA, mint lsk_ keys, CLI login
uploads identity keys, owner pushes an encrypted .env, teammate invited ->
accepted -> granted -> pulls the exact file. Server stores ciphertext only.
Full workspace build + tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a `team` credential provider + team/member management so teammates can
share secrets by email instead of passing .env files over chat. Fully E2E:
the server only ever stores ciphertext, per-member sealed vault keys, and
public keys — it never sees a plaintext value or the vault DEK.
Plugin (@logicsrc/plugin-credential-sharing)
- crypto.ts: X25519 identity keys, per-vault DEK (secretbox), DEK sealed to
each member's pubkey (crypto_box_seal), value encrypt/decrypt (libsodium)
- identity.ts: local ~/.logicsrc/identity.json (0600) holding the device key
+ API token; never uploads the secret key
- client.ts: typed /api/credshare client
- providers/team.ts: `team:<slug>/<vault>` CredentialProvider (inspect,
readValues=decrypt, write=encrypt, rollback); fingerprints match env so
env<->team diffs line up
- fixes latent libsodium-wrappers ESM load bug (createRequire) here + in
github-secrets
Server (commandboard-api /api/credshare)
- zero-knowledge router: email-code auth, keys, teams, members, invites,
vaults, sealed grants, ciphertext secrets, audit; membership authz in app
- CredShareStore abstraction: in-memory (dev/tests) + Supabase (prod)
- Resend email transport for login codes + invites (no-op -> echoes locally)
- supabase migration: credshare_* tables, deny-by-default RLS
CLI
- real `logicsrc login` (email code -> token + key upload)
- `logicsrc teams create/list/invite/accept/members/vaults/grant/push/pull`
Web (logicsrc.com/teams + /teams/accept)
- management surface only (browser holds no private key, never decrypts):
login, view teams/members/vaults, invite, accept
Tests: crypto round-trip, server contract (invite->accept->push->grant->pull
+ authz boundaries), and a real HTTP+client+crypto E2E asserting the server
never holds plaintext. Full workspace build + tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reusable AdUnit component (div[data-cp-ad] + ad.js via next/script) placed
in-content on the blog index and post pages, scoped to /blog/* only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
More AEO audit fixes (the content-independent quick wins):
- Generated 1200x630 OpenGraph/Twitter card (app/opengraph-image.tsx);
drop the SVG fallback and use summary_large_image.
- /pricing page with question-style headings and FAQPage JSON-LD; clarifies
the spec/tooling is free and implementation is $250/week.
- /llms-full.txt — full markdown of the curated docs concatenated for
large-context RAG ingestion.
- GitHub link added to both navs (SPA rail + SiteShell) and Pricing nav item;
/pricing added to the sitemap.
Verified in a running build: og image renders as PNG and is referenced in
head; /pricing serves FAQ + schema; /llms-full.txt concatenates docs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Only the .rail sidebar is dark; the .workspace content area is on the
light (#f6f7f4) page background. The previous blog styling assumed a dark
workspace, so text was light-grey on white (unreadable) and the link
green was too light.
- Darken the global link color to #0a7d59 (readable on white); content
links only — rail nav stays inherited.
- Repaint .blog-content (post HTML) for a light surface: dark body text,
light code/pre, light borders.
- Blog index/post: dark titles, readable grey meta, light row borders;
light-themed footer.
- Add post thumbnails to the /blog index from featured_image.url.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add SiteShell (rail nav + workspace + footer) and wrap /blog and
/blog/[slug] in it so they share the site's dark chrome instead of
rendering as bare standalone pages.
- Style rendered post HTML (.blog-content) for the dark workspace.
- Links were `color: inherit` everywhere, so content-area links matched
body text and were invisible. Give links a distinct accent (#5ac8a6);
keep the rail nav and buttons on their own colors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the Vite single-page app + custom Node server.js with a Next.js
16.2.6 App Router app.
- proxy.ts (src/proxy.ts): www.logicsrc.com -> logicsrc.com 301 over https,
preserving path + query (the original request, now via Next 16 Proxy).
- One SSR page via an optional catch-all ([[...slug]]) that renders the same
marketing/spec page for each known top-level route (/docs, /blog, /openspec,
...) and 404s unknown paths, preserving existing canonical URLs. Markup is a
faithful server-rendered port of the old main.ts (SEO upgrade over the prior
client render); interactivity (hire-us form, CoinPay button, section scroll)
moves to a client component.
- API routes ported to app/api/**: hire-us coinpay-checkout + project-request,
oauth/coinpay start/callback/session, webhooks/coinpay. Shared logic in
src/lib/coinpay.ts (eligibility, payment-rail selection, webhook verify,
HMAC session sign/verify, cookies).
- commandboard-api (/health + /api/boards|tasks|plugins/*) is no longer mounted
in-process; next.config.ts proxies those paths to COMMANDBOARD_API_URL via
afterFiles rewrites (our own /api routes match first).
- Build/start switch to next build / next start. Contract tests rewritten to
exercise proxy.ts, the route handlers, and pure helpers directly (21 passing);
Playwright webServer updated.
Deployment (Railway): set COMMANDBOARD_API_URL to the commandboard-api service
URL and run it as its own service; root start now runs next start.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>