Commit graph

184 commits

Author SHA1 Message Date
cdc2b32cd1 OpenConnection: a setup token you paste, a bridge that honours it
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.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYae2mH3khdwiXUVzcVMDw
2026-09-13 05:08:19 +00:00
85426e2ae0
OpenServer 0.2: the provider says how to install its CLI (#171)
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>
2026-09-12 21:46:01 -07:00
df57b54bde
Breadcrumbs on every page, and a sidebar that unfolds to where you are (#170)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
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>
2026-09-12 21:04:02 -07:00
eee9ce09c5
Site IA: broad sidebar, four spec families, one registry (#169)
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>
2026-09-12 20:38:28 -07:00
a005d7c716
docs: OpenBroadcast and OpenGuest, the broadcaster-and-guest framework as OpenProfile.md sections (#168)
* 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>
2026-09-12 20:30:42 -07:00
0fe1d423df
docs: OpenThreat, one file a security tool serves about what it found in the open (#167)
* 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>
2026-09-12 20:30:22 -07:00
938bd5f632
OpenAffiliate 0.1: one file a merchant serves about the commission it pays (#166)
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>
2026-09-12 19:36:59 -07:00
8269c12b75
docs: OpenCoupon and OpenRecipe.md, the first two niche specs (#165)
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>
2026-09-12 19:16:34 -07:00
26295dd740
OpenFile and OpenDisk: the web doors onto an ipfile swarm and a paid2seed seeder (#162)
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>
2026-09-12 19:05:15 -07:00
be2d67b8c3
docs: OpenCPU, OpenMemory, OpenGPU and OpenBandwidth, the resources of a server purchase (#163)
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>
2026-09-12 18:59:05 -07:00
41c362ddd8
OpenProfile.md 0.2: a Match section for dating sites and anything else that pairs people (#164)
Rule 9, `## Match` (Dating, Matching, Partner and Looking for normalise to
it): the keys a matching platform needs, about you (Born, Gender,
Orientation, Status, Monogamy, Height, Body, Children, Wants children,
Smoking, Drinking, Cannabis, Drugs, Religion, Politics, Ethnicity,
Education, Work, Diet, Pets, Exercise, Zodiac) and about who you seek
(Seeking, For, Ages, Distance, Not). Values are kept as written and
matched loosely like Topics; unknown keys are kept; absence is unstated.

Two rules that do not degrade: Born is the one key a matching platform
must have, and a computed age under 18 keeps the profile out of any
matching context; and the section is public by nature, so a platform
stores only what the person confirmed with it and drops it when the
file does. A `## Photos` section carries image URLs, first is the lead.
"No inference" joins the deliberately-absent list.


Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 18:57:53 -07:00
6a8ba19589
OpenServer 0.1: one file a hosting provider serves about what it sells (#161)
* 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>
2026-09-12 18:35:43 -07:00
9f898d27bf
chore: hqtui ^0.5.0, so a click reaches the key bar and the dialogs (#160)
Below 1.0 a caret locks the minor, so this app was pinned to the hqtui it
was written against and would never have seen a newer one. 0.5.0 adds
click hooks to status bar items, modal buttons and backdrops, and panels,
and a double-click on every scrollable widget; all optional, nothing here
has to change to take it.

Bumped: packages/cli/package.json, package-lock.json (lockfile-only: a full npm install on the dev box
fails in a git dependency's prepare step with EALLOWSCRIPTS, unrelated to
this change, so CI is the check here).


Claude-Session: https://claude.ai/code/session_01DWtLsmAescX4Nb8QiBJd37

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 13:42:08 -07:00
ffd0695926
Serve an OpenAccess descriptor at /.well-known/openaccess.json (#159)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
Lists LogicSRC on OpenAccess hubs (openaccess.logicsrc.com) so people can
link it with OAuth 2.1 + PKCE and it honours the shared
profullstack.com/all-access entitlement. The Ed25519 public key here is
the app's credential for reporting sales; the private half is in the
logicsrc teams vault openaccess-app-keys--prod. Scopes are empty for now:
the reserved openid, email and entitlements scopes need no listing.

Spec: https://logicsrc.com/openaccess


Claude-Session: https://claude.ai/code/session_01SWRffW4ifQPUrGXJtgYWMd

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 12:27:08 -07:00
ef115fc85a
OpenAccess 0.1: OAuth 2.1 with a grant you can carry (#158)
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>
2026-09-12 12:26:15 -07:00
8951e824d5
logicsrc CLI 0.2.0: every LogicSRC tool is a word after logicsrc (#157)
OpenContext, OpenCreds, OpenOntology and OpenPRD were already registered
under the umbrella. Three were not:

- `logicsrc openmcp …`: OpenMCP lives in its own repository, so it is a
  dependency (@logicsrc/openmcp ^0.3.1, which exports ./cli for this) and
  every argument goes untouched to the same main the standalone binary runs.
  Imported on first use, because the catalog is node:sqlite (Node 24) while
  the rest of the CLI runs on 18; below the floor that one word says so and
  offers the standalone installer, which brings its own Node.
- `logicsrc openspec <anything else>`: import, export and change stay ours;
  any other word (init, list, validate, archive, show) runs OpenSpec.dev's
  own CLI (@fission-ai/openspec) as the group's default subcommand, flags
  intact. One command for a repo in compatibility mode, and the OpenSpec.dev
  half is upstream itself rather than a copy that would drift.
- `logicsrc mcp`: the LogicSRC MCP server (@profullstack/logicsrc-mcp) over
  stdio, spawned as a child because it owns the process's stdio. build:cli
  now builds that workspace.

README gets a table of every word and the standalone name it mirrors; the
OpenMCP spec page and doc mention the umbrella form.


Claude-Session: https://claude.ai/code/session_01Qh2dieNyPZ4Hx5g3XNJ1Eo

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 11:16:40 -07:00
0f6326e910
Serve LogicSRC's own OpenProfile.md, and install OpenMCP with one line (#156)
logicsrc.com/.well-known/openprofile.md was a 404 while every relay in the
OpenMCP catalog, Obscura included, named it as its operator. The site that
publishes the spec now serves its own file: Kind organization, accounts
(GitHub, blog, the catalog, the Obscura relay so the trust chain closes both
ways), topics, projects and contact. The root layout carries
rel="openprofile" and every response carries the same relation as a Link
header, per the spec's discovery rules. skill.md and llms.txt point at it.

The OpenMCP spec page and docs/openmcp.md now lead with
curl -fsSL https://openmcp.logicsrc.com/install.sh | sh instead of npx, and
the descriptor examples name logicsrc.com's real profile rather than one
profullstack.com never served.


Claude-Session: https://claude.ai/code/session_01Qh2dieNyPZ4Hx5g3XNJ1Eo

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 10:55:52 -07:00
22fdfd0c55
openmcp page: link to the live catalog at openmcp.logicsrc.com (#155)
The spec page pointed only at the GitHub reference implementation. The
catalog is running now, so the intro and the "where everything lives" list
link to openmcp.logicsrc.com to browse or point a client at, and to the
Obscura relay it hosts.


Claude-Session: https://claude.ai/code/session_018dwULHaBKAh7nbWTCqUX7D

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-12 10:37:25 -07:00
185c68e1e6
OpenProfile 0.1.1: a DID in the identity block and in Operator (#154)
did:key, did:web and AT Protocol did:plc, kept as written. A DID from a
service that also vouches for agents (CoinPay issues one per account and
lets a person's stand behind an agent's) is how Operator becomes checkable
rather than stated. myna did attaches one.


Claude-Session: https://claude.ai/code/session_01FMT2v1YxmgcDuionrfT719

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 10:28:12 -07:00
30facd71ff
Add OpenMCP: an open catalog of MCP relays (#153)
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>
2026-09-12 09:55:14 -07:00
1a2d143a23
Add OpenProfile.md: one Markdown file for who and where, people and agents alike (#152)
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>
2026-09-12 08:42:15 -07:00
00622f5882
blog: honor canonical_url so guest posts point at their source (#151)
* blog: honor canonical_url so guest posts point at their source

A post syndicated from another blog carries the original URL in
blog_posts.canonical_url (the autoblog webhook already stores it). The post
page ignored it and always self-canonicalized, so a guest post would
compete with its source for the same words. Now the page selects
canonical_url and author, sets rel=canonical to the original when present
(self otherwise), points JSON-LD mainEntityOfPage at it, and shows readers
an "Originally published on <host>" line with the author byline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxNif5tsYq4LczgG7aE8Jp

* blog: author is jsonb, render a name not [object Object]

The blog_posts.author column is jsonb (e.g. { name, url }), not text.
Extract a display name for the byline and JSON-LD instead of rendering the
object directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxNif5tsYq4LczgG7aE8Jp

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-12 08:25:21 -07:00
9f42ce222a
docs: OpenStream benchmark reports, published per release (#150)
Adds a reports section to the OpenStream spec so its claims rest on a
reproducible measurement rather than an assertion. Each report is a run of
the envelope over a defined corpus on real hardware: proof that
decompression restores every byte, that an incompressible input costs only
the framing overhead, that a compressible one saves what it claims against
the complete wire size, and how long each codec takes.

- docs/openstream/reports/ holds a machine-readable <id>.json (canonical,
  with a versioned schema) and a rendered <id>.md per report, plus a README
  on the shape and on submitting one. The seed report is nixamp 0.17.1 over
  the synthetic corpus, labelled synthetic so no one reads a padded-fixture
  number as production.
- The site renders them at /docs/openstream/reports (index) and
  /docs/openstream/reports/<id> (one report), under the dynamic /docs/[slug]
  tree so the reports routes never shadow a spec's own doc page. A small
  lib/reports.ts reads the JSON at build time; REPORTED_SPECS keeps the
  route surface explicit. sitemap includes the index and every report.
- The spec doc gains a Benchmark reports section linking there, and repeats
  the honest caveats: OpenStream frames Zstandard and gzip rather than being
  a new algorithm, synthetic padding flatters a codec, an efficient real
  feed saves little, and round-trip exactness is the one pass/fail.

The report format is produced by `nixamp compression benchmark` (in the
nixamp repo); a release runs it and commits the two files here.


Claude-Session: https://claude.ai/code/session_01MxNif5tsYq4LczgG7aE8Jp

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-12 06:23:46 -07:00
692bfa0a2a
docs: OpenStream, a lossless byte-stream relay envelope (#149)
OpenStream is the wire format nixamp uses to relay a channel or a file
between two servers: a framed stream of blocks, each compressed with an
established codec or stored verbatim, each carrying the length and SHA-256
of the bytes it stands for, ending in a marker that says the stream
finished rather than dropped. It is a framing envelope, not a compression
algorithm, and it is deliberately product-neutral: nixamp is the reference
implementation, the format carries any byte stream.

The doc gives the byte layout (16-byte stream header, 48-byte frames, both
big-endian), the mode set, the validation order, cross-language test
vectors, the negotiation, the source/channel boundary, recovery semantics,
and a conformance checklist. Published at /docs/openstream via the same
DOC_SLUGS path as every other spec; no README change, matching how
OpenJob/OpenResume (#148) landed.


Claude-Session: https://claude.ai/code/session_01MxNif5tsYq4LczgG7aE8Jp

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-12 05:53:12 -07:00
331b437724
docs: OpenJob and OpenResume.md (#148)
Some checks failed
CI / build (push) Has been cancelled
test / test (push) Has been cancelled
Two conventions for the hiring end of the agentic stack, published here beside
the other Open* specs.

OpenResume.md says a resume is a Markdown file: a document a person can read,
diff and keep, and one an agent can write without being taught a schema first.
Six conventions, every one of which degrades rather than fails, because a
resume that does not parse still has to be a usable resume.

OpenJob extends schema.org JobPosting with the three things it has no
vocabulary for: whether the employer accepts applications written with an agent
(stated, rather than discovered by silent rejection), the application form as
data so applying does not require rendering a page, and a description in
Markdown.

Both are implemented by profullstack/agenticjobs, and neither requires it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 16:16:05 -07:00
88b29da91c
Declare a showcase frame for the hqtui.com apps gallery (#147)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
hqtui.com/apps captures screenshots of applications built on the
library. The capture script takes an application directory and imports
`scripts/showcase.ts` from it, because only the application knows what a
good state looks like.

The vault browser is the right screen to show, and it is safe to show
for the same reason it was built that way: it never handles plaintext.
Everything on it is metadata -- which vaults exist, what the secrets are
called, who can decrypt them -- so a screenshot leaks nothing the screen
would not already show anyone standing behind you.

The values are invented regardless. A real team's member emails are not
ours to publish.


Claude-Session: https://claude.ai/code/session_017Df2FNu5DhinMV2soRz3cy

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 08:50:33 -07:00
ca21348fcd
Add logicsrc teams tui, a browser for team vaults (#146)
Teams on the left, their vaults in the middle, and the selected vault's
detail on the right across three tabs: secret names, who can decrypt,
and the audit trail.

It never handles plaintext, and that is the point rather than a
limitation. The server only ever holds ciphertext and this keeps it that
way: no decryption key is fetched, none is unwrapped, and there is no
keybinding that would. The secrets tab says so on screen and points at
`logicsrc teams pull`, because otherwise the first thing anyone does is
hunt for a reveal key. A value that can appear on screen can appear in a
screen share, a scrollback buffer or a recording; names are what you
need to navigate, values are what you rarely need to look at.

Names, fingerprints and versions are enough to answer the questions you
actually open this for: does the vault exist, has the rotation landed,
and who can still read it.

Notes on the shape:

  - Vaults and detail load lazily, because each is a round trip. The
    three detail calls are settled independently, so a member without
    decryption access still sees the vault's shape and a missing audit
    endpoint does not blank the secrets list.
  - Changing team resets the vault selection. The old index means
    nothing in a different team's list, and keeping it silently selects
    an unrelated vault.
  - The secrets table shows a date rather than a timestamp. Three fixed
    columns plus a name that can run to thirty characters leaves no room,
    and a truncated clock looks like data while telling you nothing.
  - The audit table gives its widest floor to the action, not the actor:
    an email truncates to something recognisable, where "secrets…" could
    be put, get or delete.

The view is split from the loader so it renders headlessly without an
authenticated client or a terminal. 17 tests cover that, including one
asserting no ciphertext reaches the screen; 226 pass across the CLI.


Claude-Session: https://claude.ai/code/session_017Df2FNu5DhinMV2soRz3cy

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 08:07:17 -07:00
7f9e493929
Release @logicsrc/openprd 0.2.0 to npm (#145)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
Published as @logicsrc/openprd@0.2.0 — the first release of this package, and
the first carrying OpenPRD 0.3 (Tech Stack and Monetization, #144).

Two things had to change for the publish to be usable:

  - The @logicsrc/validators dependency was `file:../validators`. npm publishes
    that spec verbatim, so every install outside this monorepo would have
    failed to resolve it. It is now `^0.1.0`, which is what is on the registry;
    npm workspaces still links the local package for development, since 0.1.0
    satisfies the range.
  - Added a README. Without one the npm page reads "No README data found",
    which is a poor landing surface for the reference implementation of a
    public standard. @logicsrc/schemas already ships one.

Verified by installing 0.2.0 from the registry into an empty project: it
resolves @logicsrc/validators@0.1.0 and @logicsrc/schemas@0.1.0, and the
runtime reports OPENPRD_VERSION 0.3 with ten sections, eight for 0.2.


Claude-Session: https://claude.ai/code/session_017XRNNm6pK6nPi7rJ6bJNHu

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 05:01:33 -07:00
91834179b7
Add Tech Stack and Monetization sections to OpenPRD (0.3) (#144)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
OpenPRD 0.2 fixed eight body sections, none of which asked what the thing is
built on or how it earns. The stack got chosen in the first implementation PR
instead of at review, and a PRD could be filled out completely without anyone
writing down who pays. PRD 0006 had already grown a hand-rolled
`## Business model` section, which is the gap showing.

0.3 adds two required sections between `UX Notes` and `Success Metrics`:

  - Tech Stack — languages, frameworks, datastores, third-party services, and
    anything the work must not depend on. It makes the requirements costable.
  - Monetization — the revenue model: who pays, for what, how much, and when.
    `_None._` stays a valid answer, but it now has to be said out loud.

Adding required sections would normally invalidate every document already
written, so a document is now held to the section list its own `openprd:` key
fixes. A 0.2 document keeps conforming with eight sections, forever; a 0.3
document needs ten. Adoption is per document, and `logicsrc prd validate
--expect-version 0.3` (new flag, wiring up the validator option that already
existed) reports the stragglers as OP-L-VERSION.

The front-matter schema is untouched — both additions are body sections.

Conformance bundle proves both directions: invalid/missing-monetization.md
fails with OP-C-SECTION-MISSING, and valid/legacy-0-2.md passes unedited.

This repo's own PRDs 0001-0006 stay at 0.2 as standing evidence that the
compatibility rule holds. PRD 0007 records the decision at 0.3.


Claude-Session: https://claude.ai/code/session_017XRNNm6pK6nPi7rJ6bJNHu

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 16:50:11 -07:00
ca0283caa9 Add ASDLC, the Agentic Software Development Lifecycle
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
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
2026-09-06 15:02:31 +00:00
be99e683bd
Add pay2seed, paid2seed, pay2stream and paid2stream to the OpenSwarm family (#143)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
* Add pay2seed to the OpenSwarm family: consent at upload and a paid seed market

OpenSwarm pays a seeder per verified piece served, and nothing pays anyone
to stay. An archive, a backup, a dataset waiting for its buyer or a
podcast's back catalogue earns nothing the month nobody downloads it, so
it dies the way every swarm always has. And nothing in BitTorrent says who
put a swarm there or whether they were allowed to, which is why a seeder
is presumed to be doing something wrong.

pay2seed is the member document for both halves. An attestation, signed
at upload with a fixed basis (own, licensed, open-license, public-domain,
personal) and a notice endpoint, is what a hub requires before it will
list anything; public claims get a claim window and a standing, and a
notice voids them. An offer escrows a budget at an ippay hub for a swarm,
public or private, to be held by M seeders for N days at a price per
GiB-month, bought over x402 exactly as a pass is. Seeders take leases,
prove each period by storage challenge or by a probe over the ordinary
wire, and are paid through the payee they already have. Public feeds ride
on ipdb; ipfile.pin on c0mpute is the same offer on the auction.

Also: the family table, stack diagram and registry rows; the ip seed
command group; PRD 0006; the protocol row on /openswarm.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* Split pay2seed into client and server halves, and add pay2stream and paid2stream

The rule is now in the names. pay2* is the client protocol: the side that
pays, over HTTPS, and plays. paid2* is the server protocol: the BitTorrent
side that earns. One hub implements both halves of a pair; a requester or
viewer implements only pay2*; a seeder, relay or gateway only paid2*.

pay2seed keeps consent, offers, the requester's market and notices.
paid2seed takes leases, storage challenges and probes over the wire,
GiB-month accrual and receipts, the seeder client, and the ipfile.pin
mapping.

pay2stream and paid2stream do the same for a live channel over iplive.
A broadcaster attests the channel (with the two rules that separate a
licensed rebroadcast from a stolen feed), buys relays by the hour, and
publishes listings; viewers buy tickets. Relays take leases and are
proven present by a verifier that pulls segments as a peer; a gateway is
a relay that also serves standard HLS, clear or sealed, with the M3U and
XMLTV pair every IPTV app asks for, so VLC, TiviMate, Kodi and a
television play a paid swarm with nothing installed. Ace Stream showed
BitTorrent can carry live TV to millions; this is that with consent,
payment and an open spec.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* pay2seed: encrypted by default, access as the product, a README in every swarm

The client encrypts by default and the hub never does: what the hub
manages is who may decrypt. A team is a named set of member keys with a
scope over the owner's swarms; the hub, as keeper, issues grants to
members when the owner is offline, with invitations that expire, roles,
an audit trail, and re-encryption on removal so the next version is
closed to whoever left. A few seats are free; above that the hub charges
per seat and per organisation, settled through the same pay plugins as
everything else. Seeding is priced at disk; access is where a hub earns,
and both sides earn: seeders rent disk, requesters sell access.

Public is not a fallback. Encryption off is an explicit act, and a
public swarm is attested, listed, kept and rendered exactly as a private
one is; the only difference is who can read it.

Every swarm on the market carries a README.md at its root, no
exceptions, and the attestation carries its Markdown and the hash of
the copy inside the swarm, so the hub renders it as the swarm's page
without a key. Relative links resolve into the swarm and are gated the
way the files are.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* pay2seed: 1 percent, ads on the free tier, and agents as sellers

Three things the specs did not say. The reference hub takes 1 percent of
any payment that crosses it, charged to whoever is paying and never
deducted from a seeder or a relay, so a quoted price is what the
publisher gets and a promised floor is what the seeder is paid.

Public swarms are free to fetch and free to list, and an advertisement on
the swarm README page is what pays for that. The ad is on the hub page
and nowhere else: never inside a swarm, never injected into a file, a
segment or a playlist, and never in the catalogue or the market API. A
requester who wants no ad buys a seat instead. A free-to-watch channel
works the same way.

And a requester is a key, not a person. An agent can attest what it made,
price access, sell tickets, take payment through its own payee and spend
what it earns keeping its own work online. The consent rules do not
soften because a machine signed them, and the reference hub asks an
agent public attestation to name a responsible operator key so somebody
is reachable when a notice arrives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* Fix CI: number the PRD requirements and advance the next-id assertion

Two checks the new PRD tripped, both by existing rather than by being
wrong.

The collection validator wants requirements as numbered R# entries and
0006 used a plain ordered list, so it reported OP-L-NO-REQUIREMENTS.
Rewritten as R1 to R7 with priorities, one capability per entry, and the
implementation tracking moved to a paragraph under them where it is not
pretending to be a requirement.

The MCP standards test asserts what the next free PRD id is, and its own
comment says that advances with every PRD added. Adding 0006 makes it
0007.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 19:12:45 -07:00
4fed2681ec
Add the LogicSRC OpenSwarm specification family (#142)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
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>
2026-09-05 15:05:57 -07:00
93af4770ac
Charge AI training crawlers for access (x402 gateway) (#141)
* Charge AI training crawlers for access (@profullstack/x402-gateway)

Training crawlers (GPTBot, ClaudeBot, CCBot, meta-externalagent, Bytespider,
Applebot-Extended) get 402 Payment Required with an x402 offer, or the sales
page at /crawl, and a paid pass opens the site for a day. People, search
engines and retrieval crawlers pass through untouched. robots.txt is now
generated from the same lists.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YafYxayh7Gqe5MWNNQMev2

* Type the middleware as returning Response | NextResponse

The crawl gateway answers with a plain Fetch Response.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YafYxayh7Gqe5MWNNQMev2

* Contract test awaits the now-async proxy

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YafYxayh7Gqe5MWNNQMev2

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 14:49:39 -07:00
80a36269bb
Add the LogicSRC OpenCreds specification (#140)
Some checks failed
CI / build (push) Has been cancelled
test / test (push) Has been cancelled
* 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>
2026-08-29 04:11:38 -07:00
b1805d08e5
Add SSH keys and config to credential sharing (#139)
Some checks failed
CI / build (push) Has been cancelled
test / test (push) Has been cancelled
* Add SSH keys and config to credential sharing

Private keys have lived as plaintext-on-disk files guarded only by a
passphrase. This puts them in the same end-to-end-encrypted vaults as
.env secrets, and adds an agent path so a machine can use a key without
ever writing one to its disk.

- `ssh` provider: ~/.ssh as a value bag. Files are picked by sniffing
  contents (PRIVATE KEY blocks, ssh-*/ecdsa-*/sk-* public keys) plus
  config, config.d/* and allowed_signers. known_hosts and
  authorized_keys are host-specific and access-granting, so they need
  an explicit --include.
- Each file is one secret carrying a JSON envelope of path, mode and
  body. The engine only hands write() the secrets that CHANGED, so a
  separate manifest secret would be absent whenever a key's contents
  change but the file list doesn't — self-describing values keep every
  restore total.
- `logicsrc secrets ssh push|pull|list|agent`, addressed by PERSON not
  project: the vault is ssh--<username>, which teams vaults reads as
  project ssh, env <username>. One teammate's keys never land in
  another's restore; sharing stays a deliberate teams grant.
- Both directions hold back anything that would overwrite a file that
  already differs, and say what they skipped. --force opts in. A
  restore onto a machine with its own keys is otherwise a way to lose
  them.
- Restores chmod each file back to its recorded mode; writeFileSync's
  mode applies only on create, so an existing world-readable key would
  otherwise stay world-readable. The adapter declares delete:false.
- push warns about passphrase-less private keys before they go up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Add worked examples to secrets and secrets ssh help

Commander's usage line shows only the first alias, so `logicsrc secrets`
— the spelling people actually type — was invisible in its own help.
The examples carry it, alongside the flows worth copying: link/up/down,
the ssh backup round trip, and a plan → dry-run → approve sync.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Advertise the ssh provider on the marketing page

The marketing-drift contract failed the build because `ssh` shipped in the
provider registry with no entry in MARKETING_PROOF -- which is the test
working: it exists so a provider cannot ship while the pages people
actually land on still describe the tool without it.

The proof regex is `/~\/\.ssh|SSH key/` rather than a bare `/SSH/` on
purpose. The provider grid renders every registry `name`, and this one is
"Local SSH directory", so `/SSH/` would already be satisfied by the
generated grid and the provider could ship with no copy written about it
at all -- passing the test while failing its intent. Requiring the path or
the phrase means a human wrote a sentence.

That sentence is the new block in the credential-sharing band: ~/.ssh is a
directory of files whose permission bits are load-bearing, not a set of
KEY=VALUE lines, which is the part that makes this provider different from
the other six. README already named ~/.ssh keys, so it needed no change.

apps/logicsrc-web: 75/75 contract tests pass (was 74 passed, 1 failed).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 17:03:00 -07:00
RissRIce
1cfec322ac
fix(web): validate ontology pagination (#138)
Some checks failed
CI / build (push) Has been cancelled
test / test (push) Has been cancelled
2026-08-10 18:59:16 -07:00
RissRIce
edf9a1b063
Enforce OpenContext HTTP byte limit while streaming (#136)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
2026-08-09 21:57:05 -07:00
7eba9efd10
Make the @logicsrc packages publishable (#134)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
@logicsrc/opencontext could not be installed from npm. Three defects, each of
which alone breaks a published tarball:

1. opencontext depended on "@logicsrc/validators": "file:../validators". A
   file: specifier is unresolvable for anyone installing from the registry, so
   `npm install @logicsrc/opencontext` failed outright.

2. validators imported all 50 schemas by relative path across the repository
   ("../../schemas/schemas/*.json"). That resolves inside the monorepo and
   escapes the package once published, so an installed validators could not
   load a single schema. Now imported through @logicsrc/schemas package
   exports, with a real dependency declared.

3. Three of those schemas — repo, pull-request, openprd-prd — had no entry in
   the schemas exports map, so they were unreachable by package specifier.
   Added; the map is now sorted so it stays readable as it grows.

validators also gained files/publishConfig/license so it publishes the same way
its siblings do.

Verified the way a stranger would: npm pack all three, install the tarballs
into a clean project outside the monorepo, and run the installed binary —
version, init, validate --strict (which exercises schema loading through the
package exports), and resolve --explain all succeed. Full workspace suite green.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 12:03:41 -07:00
3ab8a4b38b
Add the LogicSRC OpenContext specification (#132)
* Add the LogicSRC OpenContext specification

OpenContext is an open specification for durable, portable, permissioned,
provenance-aware context shared between humans and AI agents. It defines how
organizational knowledge is described, authorized, versioned, resolved,
audited, and handed between replaceable workers without losing institutional
state.

Follows the OpenPRD/OpenOntology pattern already in the repo: self-contained
JSON Schemas in @logicsrc/schemas, a reference implementation package, CLI
subcommands, docs, examples, and an OpenPRD record.

Schemas (8, all self-contained so a third party can fetch one file and
validate against it with no further resolution):
  manifest, object, bundle, role, provenance, decision, diagnostic,
  audit-event — registered in @logicsrc/validators and schemas:validate.

Reference implementation (@logicsrc/opencontext):
  loader with upward manifest discovery, the full resolution pipeline,
  authority/supersession, permissions, redaction, lifecycle, provenance,
  deterministic digests, doctor, search, graph, history/diff, guarded writes,
  audit events, and file/http/git/sqlite adapters.

CLI: all 15 specified commands, as a standalone `opencontext` binary and as
`logicsrc context`, sharing one implementation so the two cannot drift.

Design decisions worth noting:

- Supersession is declared, never inferred from version numbers. Inferring it
  would hide the governance failure it represents and make
  multiple-active-versions and duplicate-canonical impossible to detect.

- The bundle digest identifies the resolved context, not the moment it was
  computed, so generated_at/bundle_id/digest/as_of are excluded while objects,
  lifecycle states, exclusions and warnings are covered. That is what lets a
  decision record cite exactly the context that produced it.

- A role's own max_classification beats an inherited one, so a ceiling on a
  shared base role cannot silently cap a role deliberately granted more;
  requesting several roles at once still takes the lowest, so combining roles
  never escalates.

- Scope wildcards match whole dotted segments only. A trailing .* covers a
  subtree; an interior * matches exactly one segment. Substring matching here
  would be an access-control bug.

- --include narrows an existing scope and is applied after it, never merged
  into it, so a request can never widen what a role holds.

Verified: 226 tests across core primitives, permissions/redaction, the
resolution pipeline, security, the published conformance fixtures (13 valid,
35 invalid, 8 resolution scenarios), project behaviour, and the five shipped
examples — which are held to --strict and a 100% health score. Benchmarks meet
every published budget (resolve 1,000 objects in ~33ms against a 2s target).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Point install docs at @logicsrc/opencontext; record the npm name collision

The unscoped `opencontext` name is already published on npm by an unrelated
third party (federicodeponte/opencontext, 2.0.0), so `npx opencontext` would
install a stranger's package. Docs now use `npx @logicsrc/opencontext`; the bin
stays named `opencontext` so the command reads as the PRD specifies once
installed.

Recorded in PRD 0003 as a blocker to resolve before any publication, along with
the fact that no @logicsrc spec package has ever been published, so there is no
existing release path to slot into.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Advance the logicsrc-mcp next-PRD-id assertion to 0004

standards.test.ts asserts prd_next_id against the live prd/ directory, so
adding PRD 0003 makes the next free id 0004. The test's own comment
anticipates this: "advances with every PRD added".

Caught by CI, not locally — the earlier verification ran per-package tests for
the packages this branch touches, and logicsrc-mcp is coupled to the PRD
directory without importing from it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 11:46:11 -07:00
1bb7ba6e60
Add AgentBBS connector plugin (#131)
Some checks failed
CI / build (push) Has been cancelled
test / test (push) Has been cancelled
Declares the AgentBBS capability surface (chat, pods, arcade, ascii-live,
finger) as @logicsrc/plugin-agentbbs and registers it in the CLI registry
and CommandBoard API.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 18:43:31 -07:00
647f204f1d
chore(agentmail): modern bbs defaults (mail host, 465 implicit TLS) (#130)
resolveMailuConfig now defaults to the real bbs mail stack: address domain
bbs.profullstack.com, mail host mail.profullstack.com, SMTP 465 implicit TLS
(bbs refuses 587), IMAPS 993. Also fixes a latent mismatch where the address
domain (bbs) and the transport's from-domain check (mail) diverged with no env
set. Verified live end-to-end with only AGENTMAIL_USER/PASS supplied.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 18:43:15 -07:00
12a1d7f479
feat(credentials): link directories to team secrets (#129) 2026-08-04 17:17:04 -07:00
e4723f31b1 feat(credentials): manage team members and rotate invites
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
2026-08-04 19:16:02 +00:00
fd253b0485
perf(credshare): list a team's vaults in one query instead of two per vault (#128)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
GET /api/credshare/teams/:slug/vaults built its response in a loop, asking
the database for a grant row and a secret count once per vault. libSQL is
remote, so each of those is a network round trip, and the endpoint cost
2N+1 of them.

On a team with 176 vaults that is 353 round trips and ~10.6s of server
time. `logicsrc teams pull` resolves the vault id twice -- once planning
the sync, once reading values -- so a pull of a single ten-key vault took
~24s, nearly all of it spent listing vaults the command does not want.

Replaced with one SELECT carrying two correlated subqueries. Both are
covered by existing primary keys (credshare_secrets is keyed
(vault_id, name), credshare_vault_grants (vault_id, user_id)), so the
per-vault work becomes an index probe inside the database instead of a
round trip across the network. No schema or index change.

Measured on a local libSQL seeded to match that team -- 176 vaults, 17
secrets each -- the endpoint goes from 355 round trips to 3, and returns
identical rows.

The response shape is unchanged: hasAccess is still a real boolean rather
than the 0/1 SQLite hands back, and secretCount is still a number.

Tests pin behaviour and cost separately. The behavioural cases pass
against both the old loop and the new query, which is the point -- only
the round-trip count changed. The regression guard asserts the query
count for 3 vaults EQUALS the count for 30 rather than matching a magic
number, so any future rewrite that reintroduces per-vault I/O fails no
matter what the constant part costs. Against the old loop it reports
9 vs 63.

Two sibling endpoints have the same shape -- /teams/:slug/members and
/vaults/:id/grants both call publicKeyFor() per member. Neither is on the
pull path and both scale with member count rather than vault count, so
they are left alone here.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 22:20:31 -07:00
4c88155f08
test(web): fail the build when marketing copy drifts from shipped providers (#126)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
The last three PRs all fixed the same class of bug. /credential-sharing
and README.md are hand-written copy; the providers they advertise are a
real registry in @logicsrc/plugin-credential-sharing. Nothing connected
the two, so the `team` provider shipped on 2026-07-13 and three weeks
later both surfaces still described a five-provider tool with no mention
of teams. The docs were right the whole time -- only the pages people
actually land on had gone stale, which is worse, because it reads as
"the product cannot do this" rather than as a documentation gap.

Assert it instead. For every provider in the registry, the Credential
Sharing section and the README must say something that counts as
advertising it. The registry's own `name` cannot be the proof -- `env`
is "Local .env file" and `team` is "LogicSRC Team Vault", neither of
which is how the copy reads -- so each provider declares its own
pattern, and a provider with no declaration fails too. That way adding
a provider forces a deliberate answer about the customer-facing copy.

Verified against the bug it is meant to catch: reverting the team copy
reproduces "These providers ship but /credential-sharing never mentions
them: team", and reverting the README line reproduces the same for
sh1pt and team.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 07:18:13 -07:00
bfb536c894
ci: remove the vu1nz security scan (#127)
vu1nz reviews a diff by calling Claude, which needs ANTHROPIC_API_KEY
supplied through the ENV_FILE secret. That key is not present on this
repository, so the scanner has never reviewed a pull request. On pack
1.0.0 and 1.0.1 that failure was silent: the job reported "0 finding(s),
no high/critical issues" on a diff nothing had read, which is worse than
no scanner at all.

threatcrush-scan covers the same ground deterministically - credentials,
injection, SSRF, unsafe deserialisation, XXE, dependency tampering - with
no API key and no per-pull-request cost.

Reinstallable from the sh1pt Actions Store if the key is ever provisioned.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 07:16:41 -07:00
3440a2e4da
chore: say teams in the README, and sync the lockfile workspace versions (#125)
The README's v1.0.0 priorities listed Credential Sharing as covering
".env, Doppler, Railway variables, and GitHub Secrets" -- the same drift
just fixed on the marketing page in #123. End-to-end-encrypted team
vaults shipped on 2026-07-13 and sh1pt landed as a provider on 07-30,
so the highest-traffic surface in the repo still told readers teams did
not exist.

Separately, packages/cli and plugins/credential-sharing were bumped to
0.1.1 in their package.json without the lockfile following, so it still
recorded 0.1.0 for both. Reconciled with `npm install
--package-lock-only`; the diff is those two version fields and nothing
else. This was cosmetic rather than breaking -- `npm ci` tolerated the
mismatch, which is why CI never caught it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 06:56:57 -07:00
806e78127c
fix(openontology): migrate in one transaction, and stop timing out on slow disks (#124)
CI failed on an unrelated PR when "seeds a package and hydrates it back
identically" passed vitest's default 5s timeout. The assertions were
fine; the suite is I/O bound and the runner was slow. Two changes.

migrate() ran every DDL statement through its own client.execute(), so
migration 1's ~30 statements each became a separate durable commit and
opening a store paid ~30 fsyncs. Batch each migration into one write
transaction instead: locally a fresh migration drops from ~8.2ms to
~5.0ms, and the gap widens as fsync gets more expensive. It also closes
a real hole -- a crash part-way could previously leave the schema
half-applied while schema_migrations recorded the migration as done,
because the statements and the bookkeeping insert were not atomic.

Then give the package a 30s testTimeout. These suites drive a real
file-backed SQLite database, so their wall time is set by the host
filesystem, not by our code. The 5s default is tuned for CPU-bound unit
tests and leaves no headroom on a contended runner.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 06:38:05 -07:00
d2abd201a6
ci: add ThreatCrush security scan (#122)
Installs threatcrush-scan@1.1.0 from the sh1pt Actions Store.
Scans pull requests for hardcoded credentials, injection, SSRF, unsafe
deserialisation and dependency tampering; uploads SARIF to the Security
tab.

Report-only — it will not fail a pull request. Set the pack's failOn
input to critical,high once the existing findings are triaged.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 06:36:30 -07:00
c03ae17798
fix(web): the Credential Sharing page never mentioned team sharing (#123)
End-to-end-encrypted team vaults shipped on 2026-07-13, and
/docs/credential-sharing documents them in full. The marketing route
/credential-sharing is a separate hand-written page, and its copy was
never updated -- it listed five providers, omitted the `team` endpoint
type, and said nothing about sharing with teammates at all. Anyone
evaluating the product from that page concluded teams were unsupported.

Add a Team vaults provider card and a team-sharing block covering the
trust model (zero-knowledge relay, X25519-sealed DEKs, rotation on
departure) with the real `logicsrc teams` commands. The route metadata
and llms.txt entry had drifted the same way and also omitted sh1pt.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 06:36:08 -07:00