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>
New @logicsrc/plugin-credential-sharing: a provider-neutral secret-sync engine
with env/.env, Doppler, Railway, and GitHub Secrets adapters behind one
CredentialProvider contract.
- engine: inspect -> diff -> plan -> approve -> sync -> rollback -> audit/export
- dry-run is the default for sync; --approve writes; destructive changes gated
- fingerprint-based diffs (salted SHA-256); raw values never printed or stored in
plans/runs/audit; rollback pre-image kept in a 0600 .logicsrc vault (gitignored)
- github-secrets is write-only for values (sealed-box via libsodium), so it cannot
be a sync source or value-restoring rollback target
- CLI: real `logicsrc credentials <providers|inspect|diff|plan|approve|sync|
rollback|audit|export>` (replaces the prior stub)
- 4 JSON schemas registered in @logicsrc/validators
- flip logicsrc.com/credential-sharing band from coming-soon to available
- 37 tests pass; full env->env lifecycle verified; artifacts schema-validate
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>
Addresses the top cross-engine AEO finding — every route previously served
the homepage SPA. /about and /docs are now distinct routes with their own
server-rendered content and titles.
- /about: substantive about page (what LogicSRC is, the standards surface,
CommandBoard.run reference impl, GitHub, hire-us) — derived from public
positioning, no fabricated team.
- /docs + /docs/[slug]: render the repo's docs/*.md (curated public set) via
marked, statically generated at build (no runtime fs dependency).
- Drop about/docs from the catch-all; add doc URLs to the sitemap.
Verified in a running build: /about and /docs serve unique content with
distinct titles; /docs/[slug] renders each markdown doc.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an autoblog webhook receiver and a Supabase-backed blog to logicsrc-web
(the app had no Supabase usage before).
- Migration: blog_posts table (RLS: public reads published, service-role
writes). Applied to the linked project.
- POST /api/webhooks/blog: verifies the Standard Webhooks signature against
BLOG_WEBHOOK_SECRET via @profullstack/autoblog verifyAndParse (no admin
user — shared secret only) and upserts the post by slug.
- /blog index + /blog/[slug] render published posts from the table.
- /blog/rss.xml and /sitemap.xml are now dynamic, generated from the table;
removed the static public/sitemap.xml and public/blog/rss.xml.
- BLOG_WEBHOOK_SECRET added to .env.example.
Verified end-to-end: a signed sample post delivered 200 and appeared in the
index, post page, RSS, and sitemap; build + typecheck pass.
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>