feat: add static introduction website (#29)

* feat: add static introduction website

* feat: expand static website positioning

* feat: redesign site with original visuals

* docs(readme): add package status badges

* ci: add project readiness automation

* ci: restrict scorecard workflow permissions

* ci: remove duplicate readiness config

* ci: pin workflow actions by sha

* docs: add scorecard badge

---------

Co-authored-by: MerlinH <merlinh221@gmail.com>
This commit is contained in:
Merlin's Cat
2026-06-27 01:15:39 +10:00
committed by GitHub
co-authored by MerlinH
parent 15b8bb94e9
commit 3c52f21d90
12 changed files with 1010 additions and 8 deletions
+2 -2
View File
@@ -13,8 +13,8 @@ jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: 24.x
cache: npm
+34
View File
@@ -0,0 +1,34 @@
name: Deploy Pages
on:
push:
branches:
- main
paths:
- 'site/**'
- '.github/workflows/pages.yml'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
- uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with:
path: site
- id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
+2 -2
View File
@@ -14,8 +14,8 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: 24.x
registry-url: https://registry.npmjs.org
+33
View File
@@ -0,0 +1,33 @@
name: OpenSSF Scorecard
on:
branch_protection_rule:
push:
branches:
- main
pull_request:
schedule:
- cron: '18 4 * * 1'
workflow_dispatch:
permissions:
contents: read
jobs:
scorecard:
name: Scorecard
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- name: OSSF Scorecard action
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.json
results_format: json
publish_results: ${{ github.event_name != 'pull_request' }}
+10
View File
@@ -2,6 +2,14 @@
**Your agents write code. Truthmark maintains human-facing, Git-reviewable documentation.**
[![npm version](https://img.shields.io/npm/v/truthmark?color=cb3837&label=npm)](https://www.npmjs.com/package/truthmark)
[![CI](https://github.com/merlinhu1/truthmark/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/merlinhu1/truthmark/actions/workflows/ci.yml)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/merlinhu1/truthmark/badge)](https://scorecard.dev/viewer/?uri=github.com/merlinhu1/truthmark)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Node.js >=24](https://img.shields.io/badge/node-%3E%3D24-339933?logo=node.js&logoColor=white)](package.json)
[Website](https://merlinhu1.github.io/truthmark/) | [GitHub](https://github.com/merlinhu1/truthmark) | [User Guide](docs/user-guide.md)
[🇺🇸 English](README.md) | [🇨🇳 简体中文](docs/readmes/README.zh.md) | [🇯🇵 日本語](docs/readmes/README.ja.md) | [🇰🇷 한국어](docs/readmes/README.ko.md) | [🇩🇪 Deutsch](docs/readmes/README.de.md) | [🇫🇷 Français](docs/readmes/README.fr.md) | [🇪🇸 Español](docs/readmes/README.es.md) | [🇧🇷 Português](docs/readmes/README.pt.md) | [🇷🇺 Русский](docs/readmes/README.ru.md) | [🇸🇦 العربية](docs/readmes/README.ar.md) | [🇮🇹 Italiano](docs/readmes/README.it.md) | [🇵🇱 Polski](docs/readmes/README.pl.md) | [🇹🇷 Türkçe](docs/readmes/README.tr.md) | [🇻🇳 Tiếng Việt](docs/readmes/README.vi.md) | [🇮🇩 Bahasa Indonesia](docs/readmes/README.id.md) | [🇬🇷 Ελληνικά](docs/readmes/README.el.md)
![Truthmark banner](docs/assets/truthmark-banner.png)
@@ -199,6 +207,8 @@ keep the result reviewable in Git
The README is the storefront: fast context, quick start, and the core mental model.
The [static website](https://merlinhu1.github.io/truthmark/) is the concise public introduction for GitHub Pages.
For command-by-command usage, surface comparisons, supported platform details, configuration, routing, Portal, and examples, read the [Truthmark User Guide](docs/user-guide.md).
## Project status
+26
View File
@@ -0,0 +1,26 @@
# Static Introduction Website
Version action: none
## PR Summary
- Add a static introduction website under `site/` for GitHub Pages with original CSS-only visual design rather than copied README poster artwork.
- Add a richer tabbed truth-doc storyboard that shows a new invariant, product-promise pressure, ownership splitting, and the final reviewer packet.
- Add product-positioning sections for checkout-native operation, claim-level review, explicit route ownership, topology repair, repository-file authority, host-shaped agent guidance, and Git-reviewable handoff.
- Remove copied poster assets from the site branch; the public page no longer depends on README banner images.
- Add a Pages deployment workflow that publishes `site/**` after relevant pushes to `main` or manual dispatch.
- Link the site from the root README and document that the site is presentation, not canonical repository truth.
## Release Note
- Truthmark now has a static GitHub Pages introduction site for public onboarding, with original visual design, a truth-doc curation storyboard, and broader repository-truth positioning.
## Verification
- Served `site/` locally with `python3 -m http.server`, captured Playwright screenshots, and validated the rendered HTML response with `curl` plus Python checks.
- `/opt/data/bin/npm run test -- tests/package-files.test.ts tests/product-boundary.test.ts tests/truth/docs.test.ts` passed: 6 tests.
- `/opt/data/bin/npm run check` passed: lint, typecheck, 337 tests, and build.
- `/opt/data/bin/npm run package:check` passed: 4 tests.
- `/opt/data/bin/npx tsx src/cli/main.ts check --json` passed with no diagnostics.
- `/opt/data/bin/npx tsx src/cli/main.ts index --json` passed with no diagnostics.
- `git diff --check` passed.
+3
View File
@@ -60,6 +60,7 @@ Truthmark owns:
- host-native agent workflow surfaces such as skills, prompts, commands, managed instruction blocks, and subagents
- branch-local documentation checks, workflow indexes, impact summaries, context packs, and workflow state derived from the active checkout
- write boundaries for read-only, documentation-write, route-write, code-write, and presentation-write workflows
- the static GitHub Pages introduction site as marketing/onboarding presentation, not repository truth
- optional CLI/package helpers that improve validation or setup without becoming required for normal agent workflow execution
Truthmark workflows must remain operational from repository files alone. A design that blocks the agent workflow because a package, CLI, daemon, server, IDE plugin, or external service is missing is outside the product boundary.
@@ -91,6 +92,7 @@ Optional integrations are acceptable only when they preserve host-native agent w
7. **Local-first simplicity wins.** Add dependencies, services, or runtime layers only when they preserve the no-blockade repository-file workflow.
8. **Truth docs stay human-friendly.** Truth docs must be structured and written for maintainers to review, scan, and understand before they are optimized for agent or machine consumption.
9. **Curation beats generation.** Truthmark should route overgrown or mixed-owner docs toward Structure instead of rewarding more appended prose.
10. **Presentation is not authority.** The static introduction website may present the product, but canonical behavior remains in README, routed truth docs, source, tests, and config.
## Required Product Boundary Check
@@ -114,6 +116,7 @@ A plan that cannot answer these questions is not ready for implementation.
- Decision (2026-06-12): Human-facing readability is part of the Truthmark product boundary for canonical truth documents.
- Decision (2026-06-26): Ongoing truth-doc curation is a primary product value.
- Marketing should emphasize bounded ownership, evidence-backed updates, Git-reviewable docs, and Structure handoff for overgrown docs instead of generic documentation generation.
- Decision (2026-06-26): The GitHub Pages site is a static marketing/onboarding surface, not a documentation hosting platform or source of repository truth.
## Maintenance Notes
@@ -1,7 +1,7 @@
---
status: active
truth_kind: engineering-operations
last_reviewed: 2026-06-20
last_reviewed: 2026-06-26
---
# Release Automation
@@ -16,13 +16,26 @@ It covers GitHub workflow triggers, verification steps, and generated GitHub Act
## Current Implementation Behavior
Release and CI behavior is implemented through checked-in GitHub workflow files and the GitHub Action template renderer.
Release, CI, GitHub Pages deployment, and repository-readiness automation are implemented through checked-in GitHub workflow files and GitHub repository settings.
The npm publish workflow runs from `release/**` tag push events, with manual `workflow_dispatch` as an operator fallback. Tag-triggered publishing keeps the GitHub Actions OIDC signing certificate tied to a concrete `refs/tags/...` source ref for npm provenance verification.
The GitHub Pages workflow deploys the committed static introduction site from `site/**` after pushes to `main` that change the site or Pages workflow.
CodeQL is handled by GitHub's default setup for this repository.
Checked-in advanced CodeQL workflow configuration is intentionally absent while default setup is enabled.
OpenSSF Scorecard runs as a repository-readiness check on mainline, pull request, scheduled, manual, and branch-protection-rule events.
The Scorecard workflow does not upload SARIF and does not request `security-events: write`; it publishes Scorecard results through OIDC on non-pull-request events.
Dependency-update monitoring is managed by existing GitHub repository configuration outside this PR's checked-in workflow changes.
## Operational Surface
- GitHub Actions workflows under `.github/workflows/**`
- static introduction site files under `site/**`
- GitHub Action template rendering in `src/templates/github-action.ts`
## Runtime Topology
@@ -31,7 +44,9 @@ Automation runs in GitHub Actions. There is no Truthmark daemon or persistent ru
## Configuration
- GitHub workflow YAML files define CI and release triggers.
- GitHub workflow YAML files define CI, release, Pages deployment, and Scorecard triggers.
- Checked-in workflow actions are pinned to full commit SHAs, with inline comments preserving the upstream action version tag used to choose each SHA.
- GitHub repository settings own CodeQL default setup and existing dependency-update monitoring.
- `src/templates/github-action.ts` owns generated GitHub Action template behavior.
## Permissions
@@ -40,9 +55,12 @@ Permissions are owned by the checked-in GitHub workflow and action template defi
This doc does not add permissions beyond those source files.
The Scorecard workflow keeps workflow-level token permissions read-only and grants `id-token: write` only to the Scorecard job.
## Deployment And Rollback
- Workflow changes deploy when repository workflow files are committed to the target branch.
- Static introduction site changes deploy through GitHub Pages after they merge to `main`.
- Rollback is a normal Git revert or follow-up workflow-file change.
## Availability And Observability
@@ -57,6 +75,12 @@ This doc does not add permissions beyond those source files.
## Engineering Decisions
- Decision (2026-06-14): Release automation truth is engineering/operational truth because it describes current repository mechanics.
- Decision (2026-06-26): GitHub Pages deploys only the committed static introduction site under `site/**`.
- The site is a presentation artifact; Markdown truth docs remain canonical.
- Decision (2026-06-26): Project-readiness checks use standard GitHub-native scanners before custom readiness badges or claims.
- CodeQL default setup covers code scanning without a checked-in advanced workflow.
- OpenSSF Scorecard covers external repository-health/security heuristics.
- Existing GitHub repository configuration covers dependency-update monitoring.
## Rationale
@@ -69,11 +93,15 @@ Release automation is documented as operations truth because failures, permissio
## Maintenance Notes
Update when CI triggers, release prerequisites, publish steps, or action templates change.
Update when CI triggers, release prerequisites, publish steps, Pages deployment steps, checked-in readiness scans, or action templates change.
## Source References
- ../../../../.github/workflows/ci.yml
- ../../../../.github/workflows/pages.yml
- ../../../../src/templates/github-action.ts
- ../../../../.github/workflows/scorecard.yml
- ../../../../site/index.html
- `.github/workflows/**`
- `site/**`
- `src/templates/github-action.ts`
+3
View File
@@ -105,12 +105,15 @@ Area files:
Code surface:
- .github/workflows/\*\*
- site/\*\*
- src/templates/github-action.ts
Update truth when:
- CI verification steps or triggers change
- release publishing prerequisites or publish steps change
- checked-in repository-readiness scans change
- GitHub Pages deployment or static introduction site behavior changes
## Repository Intelligence
@@ -20,12 +20,15 @@ truth_documents:
Code surface:
- .github/workflows/\*\*
- site/\*\*
- src/templates/github-action.ts
Update truth when:
- CI verification steps or triggers change
- release publishing prerequisites or publish steps change
- CodeQL, Scorecard, or other checked-in repository-readiness automation changes
- GitHub Pages deployment or static introduction site behavior changes
- GitHub Action examples or action template rendering changes
## Source References
View File
+862
View File
@@ -0,0 +1,862 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Truthmark — the branch explains itself</title>
<meta name="description" content="Truthmark helps AI-assisted branches carry accurate, reviewable repository truth alongside code changes.">
<meta property="og:title" content="Truthmark — the branch explains itself">
<meta property="og:description" content="A repository-native review layer for code, decisions, and current truth.">
<meta property="og:type" content="website">
<meta name="theme-color" content="#07131f">
<style>
:root {
color-scheme: dark;
--ink: #07131f;
--ink-2: #0a1a2a;
--ink-3: #102236;
--paper: #f5f7ef;
--paper-2: #e8f2dd;
--text: #f8fbf2;
--muted: #b9c7d6;
--dim: #7f90a3;
--green: #8ee66b;
--green-2: #58bf43;
--lime-glow: rgba(142, 230, 107, 0.2);
--cyan: #77d9ff;
--amber: #f1c765;
--rose: #ff8d9a;
--line: rgba(220, 236, 255, 0.16);
--line-strong: rgba(220, 236, 255, 0.28);
--panel: rgba(255, 255, 255, 0.045);
--panel-2: rgba(255, 255, 255, 0.075);
--shadow: 0 30px 90px rgba(0, 0, 0, 0.36);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
min-height: 100vh;
color: var(--text);
background:
radial-gradient(circle at 18% 6%, rgba(142, 230, 107, 0.18), transparent 28rem),
radial-gradient(circle at 82% 10%, rgba(119, 217, 255, 0.13), transparent 32rem),
radial-gradient(circle at 50% 56%, rgba(241, 199, 101, 0.06), transparent 38rem),
linear-gradient(180deg, #020812 0%, var(--ink) 36%, #050b12 100%);
overflow-x: hidden;
}
body::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
background-image:
linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
background-size: 48px 48px;
mask-image: linear-gradient(180deg, rgba(0,0,0,0.75), transparent 72%);
}
a { color: inherit; }
.shell {
width: min(1240px, calc(100% - 48px));
margin: 0 auto;
}
.nav {
position: sticky;
top: 0;
z-index: 50;
border-bottom: 1px solid rgba(220,236,255,0.08);
background: rgba(3, 10, 18, 0.78);
backdrop-filter: blur(18px);
}
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 74px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 12px;
text-decoration: none;
font-weight: 780;
letter-spacing: -0.03em;
}
.glyph {
position: relative;
width: 38px;
height: 38px;
border: 1px solid rgba(142,230,107,0.55);
border-radius: 13px;
background: linear-gradient(145deg, rgba(142,230,107,0.2), rgba(119,217,255,0.1));
box-shadow: 0 0 30px rgba(142,230,107,0.18);
}
.glyph::before,
.glyph::after {
content: "";
position: absolute;
border-radius: 999px;
background: var(--green);
}
.glyph::before { width: 16px; height: 3px; left: 10px; top: 18px; transform: rotate(42deg); }
.glyph::after { width: 23px; height: 3px; left: 15px; top: 16px; transform: rotate(-48deg); }
.nav-links {
display: flex;
align-items: center;
gap: 21px;
color: var(--muted);
font-size: 0.94rem;
font-weight: 620;
}
.nav-links a {
text-decoration: none;
transition: color 150ms ease;
}
.nav-links a:hover { color: var(--text); }
.button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
padding: 0 17px;
border: 1px solid var(--line-strong);
border-radius: 999px;
background: rgba(255,255,255,0.045);
color: var(--text);
font-weight: 720;
text-decoration: none;
box-shadow: 0 12px 34px rgba(0,0,0,0.22);
}
.button.primary {
color: #06110a;
border-color: rgba(142,230,107,0.92);
background: linear-gradient(180deg, #a4f483, #62c94b);
}
.hero {
display: grid;
grid-template-columns: 0.9fr 1.1fr;
gap: 52px;
align-items: center;
min-height: calc(100vh - 74px);
padding: 76px 0 88px;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 7px 12px;
border: 1px solid rgba(142,230,107,0.28);
border-radius: 999px;
background: rgba(142,230,107,0.09);
color: #d9ffd0;
font-size: 0.9rem;
font-weight: 760;
letter-spacing: -0.01em;
}
.pulse {
width: 8px;
height: 8px;
border-radius: 999px;
background: var(--green);
box-shadow: 0 0 16px rgba(142,230,107,0.8);
}
h1 {
margin: 22px 0 20px;
font-size: clamp(3.35rem, 6.7vw, 6.6rem);
line-height: 0.91;
letter-spacing: -0.078em;
text-wrap: balance;
}
.lead {
max-width: 740px;
margin: 0;
color: var(--muted);
font-size: clamp(1.18rem, 1.55vw, 1.48rem);
line-height: 1.58;
letter-spacing: -0.02em;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 14px;
margin-top: 32px;
}
.signals {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
margin-top: 34px;
max-width: 690px;
}
.signal {
padding: 15px;
border: 1px solid var(--line);
border-radius: 16px;
background: var(--panel);
}
.signal strong { display: block; margin-bottom: 6px; letter-spacing: -0.025em; }
.signal span { color: var(--dim); font-size: 0.92rem; line-height: 1.42; }
.stage {
position: relative;
min-height: 680px;
border: 1px solid var(--line-strong);
border-radius: 34px;
background:
radial-gradient(circle at 70% 16%, rgba(142,230,107,0.17), transparent 18rem),
radial-gradient(circle at 22% 80%, rgba(119,217,255,0.1), transparent 20rem),
rgba(255,255,255,0.045);
box-shadow: var(--shadow);
overflow: hidden;
}
.stage::before {
content: "";
position: absolute;
inset: 42px;
border: 1px dashed rgba(220,236,255,0.13);
border-radius: 999px;
transform: rotate(-14deg);
}
.orbit {
position: absolute;
border: 1px solid var(--line);
background: rgba(4, 12, 22, 0.78);
backdrop-filter: blur(8px);
box-shadow: 0 18px 60px rgba(0,0,0,0.28);
}
.orbit.core {
left: 50%; top: 50%; transform: translate(-50%, -50%);
width: min(390px, 72%);
border-radius: 28px;
padding: 26px;
z-index: 4;
}
.core h2 {
margin: 0 0 12px;
font-size: 2rem;
line-height: 1.04;
letter-spacing: -0.055em;
}
.core p { margin: 0; color: var(--muted); line-height: 1.55; }
.route-line {
display: grid;
grid-template-columns: 18px 1fr auto;
gap: 10px;
align-items: center;
margin-top: 18px;
padding: 12px;
border: 1px solid rgba(220,236,255,0.12);
border-radius: 14px;
color: #dfe9f6;
font: 0.86rem/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
background: rgba(255,255,255,0.035);
}
.route-line i {
display: block;
width: 11px;
height: 11px;
border-radius: 999px;
background: var(--green);
box-shadow: 0 0 14px rgba(142,230,107,0.6);
}
.route-line em { color: var(--dim); font-style: normal; }
.node {
position: absolute;
width: 172px;
padding: 16px;
border-radius: 20px;
}
.node strong { display: block; margin-bottom: 7px; letter-spacing: -0.02em; }
.node span { display: block; color: var(--dim); font-size: 0.86rem; line-height: 1.38; }
.node.a { top: 44px; left: 54px; }
.node.b { top: 88px; right: 42px; }
.node.c { left: 42px; bottom: 76px; }
.node.d { right: 58px; bottom: 52px; }
.rail {
position: absolute;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(142,230,107,0.62), transparent);
transform-origin: left center;
opacity: 0.7;
}
.rail.r1 { width: 260px; top: 206px; left: 180px; transform: rotate(24deg); }
.rail.r2 { width: 230px; top: 224px; right: 170px; transform: rotate(145deg); }
.rail.r3 { width: 260px; bottom: 214px; left: 180px; transform: rotate(-22deg); }
.rail.r4 { width: 230px; bottom: 202px; right: 184px; transform: rotate(205deg); }
.section {
padding: 92px 0;
border-top: 1px solid rgba(220,236,255,0.08);
}
.section-header {
max-width: 860px;
margin-bottom: 34px;
}
h2.section-title,
.section-header h2 {
margin: 0 0 14px;
font-size: clamp(2.35rem, 4.5vw, 4.6rem);
line-height: 0.96;
letter-spacing: -0.068em;
text-wrap: balance;
}
.section-header p {
margin: 0;
color: var(--muted);
font-size: 1.16rem;
line-height: 1.62;
letter-spacing: -0.015em;
}
.map-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 14px;
}
.surface-card {
position: relative;
min-height: 250px;
padding: 22px;
border: 1px solid var(--line);
border-radius: 22px;
background: var(--panel);
overflow: hidden;
}
.surface-card::after {
content: attr(data-index);
position: absolute;
right: 18px;
bottom: 12px;
color: rgba(248,251,242,0.08);
font-size: 4.8rem;
font-weight: 800;
letter-spacing: -0.08em;
}
.surface-card:hover { border-color: rgba(142,230,107,0.38); background: var(--panel-2); }
.surface-card h3 {
position: relative;
margin: 0 0 10px;
font-size: 1.35rem;
line-height: 1.08;
letter-spacing: -0.04em;
z-index: 1;
}
.surface-card p {
position: relative;
margin: 0;
color: var(--muted);
line-height: 1.55;
z-index: 1;
}
.mini-kicker {
display: inline-flex;
margin-bottom: 18px;
padding: 5px 9px;
border: 1px solid rgba(142,230,107,0.32);
border-radius: 999px;
color: var(--green);
background: rgba(142,230,107,0.08);
font-size: 0.72rem;
font-weight: 820;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.timeline {
display: grid;
grid-template-columns: 310px 1fr;
gap: 18px;
align-items: stretch;
}
.tabs {
display: grid;
gap: 12px;
}
.tab {
width: 100%;
padding: 18px;
border: 1px solid var(--line);
border-radius: 18px;
background: var(--panel);
color: var(--muted);
text-align: left;
cursor: pointer;
font: inherit;
}
.tab strong {
display: block;
margin-bottom: 7px;
color: var(--text);
font-size: 1.04rem;
letter-spacing: -0.03em;
}
.tab[aria-selected="true"] {
border-color: rgba(142,230,107,0.56);
background: rgba(142,230,107,0.12);
color: #dcefd7;
}
.panel {
display: none;
min-height: 640px;
border: 1px solid var(--line-strong);
border-radius: 26px;
background: rgba(4, 12, 22, 0.74);
box-shadow: var(--shadow);
overflow: hidden;
}
.panel.active { display: block; }
.panel-head {
display: flex;
justify-content: space-between;
gap: 16px;
padding: 18px 22px;
border-bottom: 1px solid var(--line);
}
.panel-head strong { letter-spacing: -0.03em; }
.status-pill {
display: inline-flex;
align-items: center;
padding: 5px 9px;
border: 1px solid rgba(142,230,107,0.36);
border-radius: 999px;
color: var(--green);
background: rgba(142,230,107,0.09);
font-size: 0.76rem;
font-weight: 820;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.panel-grid {
display: grid;
grid-template-columns: 0.9fr 1.1fr;
min-height: 590px;
}
.evidence,
.truth-sheet {
padding: 24px;
}
.evidence {
border-right: 1px solid var(--line);
background: rgba(255,255,255,0.025);
}
.label {
display: block;
margin-bottom: 14px;
color: var(--green);
font-size: 0.78rem;
font-weight: 850;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.evidence-list { display: grid; gap: 11px; }
.file-row,
.claim-row {
padding: 12px 13px;
border: 1px solid rgba(220,236,255,0.11);
border-radius: 12px;
background: rgba(255,255,255,0.035);
color: #dfe9f6;
font: 0.88rem/1.42 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.truth-sheet h3 {
margin: 0 0 12px;
font-size: 1.48rem;
line-height: 1.1;
letter-spacing: -0.045em;
}
.truth-sheet h4 {
margin: 18px 0 8px;
color: var(--green);
font-size: 0.96rem;
letter-spacing: -0.01em;
}
.truth-sheet p,
.truth-sheet li { color: var(--muted); line-height: 1.55; }
.truth-sheet ul { margin: 8px 0 0; padding-left: 18px; }
.add { color: #b8f5a4; }
.edit { color: #f5d37d; }
.move { color: #9fdcff; }
.quiet { color: #9dafc4; }
.split-view {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
}
.lane {
padding: 26px;
border: 1px solid var(--line);
border-radius: 24px;
background: var(--panel);
}
.lane h3 {
margin: 0 0 12px;
font-size: 1.7rem;
letter-spacing: -0.055em;
}
.lane p,
.lane li { color: var(--muted); line-height: 1.58; }
.lane ul { padding-left: 18px; }
.diagram {
margin-top: 28px;
padding: 24px;
border: 1px solid var(--line);
border-radius: 26px;
background:
linear-gradient(135deg, rgba(142,230,107,0.08), transparent 38%),
rgba(255,255,255,0.035);
}
.diagram-grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 12px;
align-items: center;
}
.diagram-cell {
min-height: 118px;
display: grid;
place-items: center;
padding: 14px;
border: 1px solid rgba(220,236,255,0.13);
border-radius: 18px;
background: rgba(4,12,22,0.58);
text-align: center;
color: var(--muted);
line-height: 1.38;
}
.diagram-cell strong { color: var(--text); display: block; margin-bottom: 6px; }
.arrow { color: var(--green); font-size: 1.8rem; text-align: center; }
.install {
display: grid;
grid-template-columns: 0.85fr 1.15fr;
gap: 22px;
align-items: stretch;
}
.terminal {
border: 1px solid var(--line-strong);
border-radius: 24px;
background: rgba(3,9,18,0.78);
box-shadow: var(--shadow);
overflow: hidden;
}
.terminal-top {
display: flex;
gap: 8px;
padding: 16px 18px;
border-bottom: 1px solid var(--line);
background: rgba(255,255,255,0.035);
}
.term-dot { width: 10px; height: 10px; border-radius: 999px; background: #5f6b7a; }
.term-dot:nth-child(2) { background: #94a0ae; }
.term-dot:nth-child(3) { background: var(--green); }
pre {
margin: 0;
padding: 25px;
color: #dfe9f6;
white-space: pre-wrap;
font: 500 0.97rem/1.78 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.prompt { color: var(--green); }
.comment { color: var(--dim); }
.footer {
display: flex;
justify-content: space-between;
gap: 24px;
padding: 44px 0 64px;
border-top: 1px solid rgba(220,236,255,0.08);
color: var(--dim);
}
.footer a { color: var(--text); text-decoration: none; }
@media (max-width: 1080px) {
.hero,
.timeline,
.panel-grid,
.split-view,
.install { grid-template-columns: 1fr; }
.stage { min-height: 620px; }
.map-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.diagram-grid { grid-template-columns: 1fr; }
.arrow { transform: rotate(90deg); }
.evidence { border-right: 0; border-bottom: 1px solid var(--line); }
.nav-links { display: none; }
}
@media (max-width: 680px) {
.shell { width: min(100% - 28px, 1240px); }
.hero { padding-top: 52px; }
.signals,
.map-grid { grid-template-columns: 1fr; }
.stage { min-height: 720px; }
.node { width: 145px; }
.node.a { top: 30px; left: 20px; }
.node.b { top: 54px; right: 20px; }
.node.c { left: 20px; bottom: 58px; }
.node.d { right: 20px; bottom: 40px; }
.rail { display: none; }
.footer { flex-direction: column; }
}
</style>
</head>
<body>
<header class="nav">
<div class="shell nav-inner">
<a class="brand" href="#top" aria-label="Truthmark home">
<span class="glyph" aria-hidden="true"></span>
<span>Truthmark</span>
</a>
<nav class="nav-links" aria-label="Primary navigation">
<a href="#surface-map">Surface map</a>
<a href="#storyboard">Storyboard</a>
<a href="#lanes">Lanes</a>
<a href="#workflow">Workflow</a>
<a href="https://github.com/merlinhu1/truthmark">GitHub</a>
</nav>
</div>
</header>
<main id="top">
<section class="shell hero">
<div>
<div class="eyebrow"><span class="pulse"></span>Repository truth carried by the branch</div>
<h1>The branch should explain itself.</h1>
<p class="lead">Truthmark gives AI-assisted work a reviewable truth layer: current claims, ownership routes, product promises, and implementation facts travel with the same Git branch as the code.</p>
<div class="hero-actions">
<a class="button primary" href="https://github.com/merlinhu1/truthmark">View on GitHub</a>
<a class="button" href="#storyboard">Open the demo</a>
</div>
<div class="signals" aria-label="Truthmark summary signals">
<div class="signal"><strong>Checkout-native</strong><span>After setup, normal agent work can proceed from committed repository files.</span></div>
<div class="signal"><strong>Claim-level review</strong><span>Docs change as small, source-backed claims instead of anonymous summaries.</span></div>
<div class="signal"><strong>Topology aware</strong><span>When truth gets too broad, ownership gets repaired rather than hidden.</span></div>
<div class="signal"><strong>Host-shaped</strong><span>Instructions meet agents in their existing coding environments.</span></div>
</div>
</div>
<aside class="stage" aria-label="Original Truthmark concept illustration">
<div class="rail r1"></div><div class="rail r2"></div><div class="rail r3"></div><div class="rail r4"></div>
<div class="orbit node a"><strong>Code delta</strong><span>Changed files enter through the active checkout.</span></div>
<div class="orbit node b"><strong>Route owner</strong><span>The repo says which truth surface owns the claim.</span></div>
<div class="orbit node c"><strong>Human review</strong><span>Truth diffs sit beside implementation diffs.</span></div>
<div class="orbit node d"><strong>Agent host</strong><span>Codex, Claude Code, Copilot, Cursor, OpenCode, and peers read local guidance.</span></div>
<div class="orbit core">
<h2>Branch truth ledger</h2>
<p>A compact view of what this branch changed, which claims are affected, and which docs need curation before handoff.</p>
<div class="route-line"><i></i><span>src/webhooks/retry.ts</span><em>engineering/webhook-delivery.md</em></div>
<div class="route-line"><i></i><span>README reliability copy</span><em>product/webhook-reliability.md</em></div>
<div class="route-line"><i></i><span>operator replay UI</span><em>engineering/webhook-replay.md</em></div>
</div>
</aside>
</section>
<section id="surface-map" class="shell section">
<div class="section-header">
<h2>More than a docs generator.</h2>
<p>Truthmark is best understood as a repository-truth workflow surface. The value is not one feature; it is how several constraints reinforce each other.</p>
</div>
<div class="map-grid">
<article class="surface-card" data-index="01"><span class="mini-kicker">Operation</span><h3>No resident service in the critical path</h3><p>Helpers can validate and refresh, but the daily closeout path is designed to remain readable from the checkout.</p></article>
<article class="surface-card" data-index="02"><span class="mini-kicker">Continuity</span><h3>Truth is maintained after the first draft</h3><p>Code changes keep revisiting the mapped docs, so documentation becomes a living review artifact rather than a launch-week export.</p></article>
<article class="surface-card" data-index="03"><span class="mini-kicker">Architecture</span><h3>Routes make ownership explicit</h3><p>Files, areas, and truth docs are connected by committed routing metadata instead of implicit tribal knowledge.</p></article>
<article class="surface-card" data-index="04"><span class="mini-kicker">Governance</span><h3>Product truth and mechanics do not collapse together</h3><p>User-facing promises can link to implementation reality without becoming the same document.</p></article>
<article class="surface-card" data-index="05"><span class="mini-kicker">Review</span><h3>Claims are small enough for Git</h3><p>The desired unit is a durable claim per line or bullet, making truth updates easy to inspect in pull requests.</p></article>
<article class="surface-card" data-index="06"><span class="mini-kicker">Portability</span><h3>Agent guidance follows the repo</h3><p>Generated skills, prompts, commands, and instruction blocks are committed where the agent can read them.</p></article>
<article class="surface-card" data-index="07"><span class="mini-kicker">Repair</span><h3>Overgrown docs trigger structure work</h3><p>When a file starts mixing owners, Truth Structure is the product answer, not a larger paragraph.</p></article>
<article class="surface-card" data-index="08"><span class="mini-kicker">Boundary</span><h3>Repository files outrank session memory</h3><p>Current truth lives where maintainers can diff, revert, blame, and review it.</p></article>
</div>
</section>
<section id="storyboard" class="shell section">
<div class="section-header">
<h2>A truth document over time.</h2>
<p>This demo is fictional, but the workflow is concrete: create the right doc, update it when behavior changes, and split it when ownership gets crowded.</p>
</div>
<div class="timeline">
<div class="tabs" role="tablist" aria-label="Truth document curation timeline">
<button class="tab" role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1"><strong>Episode 1 · New invariant</strong>A retry policy appears in code and needs a current-state owner.</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2"><strong>Episode 2 · Promise pressure</strong>Marketing copy changes; product truth and engineering truth diverge.</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="panel-3" id="tab-3"><strong>Episode 3 · Ownership split</strong>Replay, delivery, audit, and alerts no longer belong in one file.</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="panel-4" id="tab-4"><strong>Episode 4 · Reviewer packet</strong>The pull request shows implementation, evidence, and truth changes together.</button>
</div>
<article class="panel active" role="tabpanel" id="panel-1" aria-labelledby="tab-1">
<div class="panel-head"><strong>Truth Document creates a narrow engineering owner.</strong><span class="status-pill">created</span></div>
<div class="panel-grid">
<div class="evidence"><span class="label">Evidence read</span><div class="evidence-list"><div class="file-row">src/webhooks/retry-policy.ts</div><div class="file-row">tests/webhooks/retry-policy.test.ts</div><div class="file-row">config/webhook-delivery.yml</div></div></div>
<div class="truth-sheet"><span class="label">Created doc</span><h3>Webhook delivery behavior</h3><h4>Current behavior</h4><ul><li class="add">Failed deliveries are retried three times.</li><li class="add">Backoff starts at 30 seconds and doubles per attempt.</li><li class="add">Manual replay remains available after automatic retries stop.</li></ul><h4>Non-goals</h4><ul><li class="quiet">The service does not claim exactly-once delivery.</li></ul></div>
</div>
</article>
<article class="panel" role="tabpanel" id="panel-2" aria-labelledby="tab-2">
<div class="panel-head"><strong>Truth Sync separates a user promise from runtime mechanics.</strong><span class="status-pill">curated</span></div>
<div class="panel-grid">
<div class="evidence"><span class="label">Branch changes</span><div class="evidence-list"><div class="file-row">README.md adds operator reliability copy</div><div class="file-row">src/webhooks/replay-audit.ts</div><div class="file-row">tests/webhooks/replay-audit.test.ts</div></div></div>
<div class="truth-sheet"><span class="label">Two updated surfaces</span><h3>Product promise vs implementation fact</h3><h4>Product truth</h4><ul><li class="add">Operators can inspect failed delivery history before replay.</li><li class="add">The product presents replay as an operator recovery tool, not an automatic guarantee.</li></ul><h4>Engineering truth</h4><ul><li class="edit">Replay writes an audit row with actor, delivery id, and timestamp.</li><li class="quiet">The retry limit remains unchanged.</li></ul></div>
</div>
</article>
<article class="panel" role="tabpanel" id="panel-3" aria-labelledby="tab-3">
<div class="panel-head"><strong>Truth Structure changes the shape before prose gets heavier.</strong><span class="status-pill">split</span></div>
<div class="panel-grid">
<div class="evidence"><span class="label">Topology pressure</span><div class="evidence-list"><div class="file-row">delivery retries + manual replay + alert thresholds + export audit</div><div class="file-row">one doc now has four owners</div><div class="file-row">future edits would be ambiguous</div></div></div>
<div class="truth-sheet"><span class="label">New ownership map</span><h3>Owned docs after split</h3><ul><li class="move">engineering/webhook-delivery.md owns retry and delivery lifecycle.</li><li class="move">engineering/webhook-replay.md owns operator replay behavior.</li><li class="move">engineering/webhook-audit.md owns audit rows and export format.</li><li class="move">product/webhook-reliability.md owns customer-facing recovery promises.</li></ul></div>
</div>
</article>
<article class="panel" role="tabpanel" id="panel-4" aria-labelledby="tab-4">
<div class="panel-head"><strong>The reviewer sees a small packet, not a mystery transcript.</strong><span class="status-pill">review</span></div>
<div class="panel-grid">
<div class="evidence"><span class="label">Pull request surface</span><div class="evidence-list"><div class="file-row">code diff: retry + replay behavior</div><div class="file-row">test diff: replay audit coverage</div><div class="file-row">truth diff: product + engineering docs</div><div class="file-row">route diff: ownership split</div></div></div>
<div class="truth-sheet"><span class="label">Reviewer questions</span><h3>What the PR now answers</h3><ul><li class="add">Which user promise changed?</li><li class="add">Which implementation behavior supports it?</li><li class="add">Which files own future updates?</li><li class="add">Which claims should be rejected if the code changes again?</li></ul></div>
</div>
</article>
</div>
</section>
<section id="lanes" class="shell section">
<div class="section-header"><h2>Two lanes, linked on purpose.</h2><p>Truthmark can let product and engineering documents reference each other without forcing them into the same voice or authority level.</p></div>
<div class="split-view">
<article class="lane"><span class="mini-kicker">Promise lane</span><h3>What the project says users can rely on</h3><p>This lane is for product capabilities, boundaries, acceptance criteria, and non-goals.</p><ul><li>Operators can inspect replay history.</li><li>The workflow is repository-native by default.</li><li>Generated presentation pages are not canonical truth.</li></ul></article>
<article class="lane"><span class="mini-kicker">Mechanics lane</span><h3>What the current implementation actually does</h3><p>This lane is for runtime behavior, contracts, operations, architecture, and failure modes.</p><ul><li>Backoff doubles after each failed delivery attempt.</li><li>GitHub Pages deploys the committed static site under site/**.</li><li>Generated surfaces refresh when rendered content changes.</li></ul></article>
</div>
</section>
<section id="workflow" class="shell section">
<div class="section-header"><h2>The workflow is deliberately boring at runtime.</h2><p>Truthmark's ambition is in the repository model, not in requiring every contributor to adopt a new always-on system.</p></div>
<div class="diagram">
<div class="diagram-grid" aria-label="Truthmark workflow diagram">
<div class="diagram-cell"><strong>1. Setup</strong><span>Configure routes and install agent-facing surfaces.</span></div>
<div class="arrow"></div>
<div class="diagram-cell"><strong>2. Work</strong><span>Agent changes code in its normal host.</span></div>
<div class="arrow"></div>
<div class="diagram-cell"><strong>3. Closeout</strong><span>Mapped truth docs are checked, edited, split, or left unchanged with evidence.</span></div>
</div>
</div>
</section>
<section id="install" class="shell section install">
<div class="section-header"><h2>Start with the repo, not a server.</h2><p>Install once, commit the workflow surface, and let future branches carry their truth updates through normal review.</p></div>
<div class="terminal" aria-label="Install commands"><div class="terminal-top"><span class="term-dot"></span><span class="term-dot"></span><span class="term-dot"></span></div><pre><span class="prompt">$</span> cd /path/to/your-repo
<span class="prompt">$</span> npm install -g truthmark
<span class="prompt">$</span> truthmark config
<span class="prompt">$</span> truthmark init
<span class="prompt">$</span> truthmark check
<span class="comment"># After setup, agent guidance and truth routes live in the checkout.</span></pre></div>
</section>
</main>
<footer class="shell footer"><div>Truthmark keeps current repository truth reviewable where code review already happens.</div><div><a href="https://github.com/merlinhu1/truthmark">GitHub</a> · <a href="https://github.com/merlinhu1/truthmark/blob/main/docs/user-guide.md">User guide</a></div></footer>
<script>
const tabs = Array.from(document.querySelectorAll('[role="tab"]'));
const panels = Array.from(document.querySelectorAll('[role="tabpanel"]'));
function selectTab(tab) {
tabs.forEach((item) => item.setAttribute('aria-selected', String(item === tab)));
panels.forEach((panel) => panel.classList.toggle('active', panel.id === tab.getAttribute('aria-controls')));
}
tabs.forEach((tab) => {
tab.addEventListener('click', () => selectTab(tab));
tab.addEventListener('keydown', (event) => {
const index = tabs.indexOf(tab);
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {
event.preventDefault();
const next = tabs[(index + 1) % tabs.length];
next.focus();
selectTab(next);
}
if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {
event.preventDefault();
const previous = tabs[(index - 1 + tabs.length) % tabs.length];
previous.focus();
selectTab(previous);
}
});
});
</script>
</body>
</html>