Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export default function Layout({ children, frontmatter }) {
<span className="header-divider" aria-hidden="true" />
<nav className="header-nav" aria-label="Main navigation">
<Link href="/getting-started/quickstart" className="header-nav-link">Docs</Link>
<Link href="/tools/scaffold" className="header-nav-link">Tools</Link>
<Link href="/tools/hypercerts-agent-skills" className="header-nav-link">Tools</Link>
</nav>
<div style={{ flex: 1 }} />
<button
Expand Down
1 change: 0 additions & 1 deletion components/SearchDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const QUICK_LINK_PATHS = [
'/getting-started/quickstart',
'/core-concepts/what-is-hypercerts',
'/core-concepts/hypercerts-core-data-model',
'/tools/scaffold',
'/architecture/overview',
'/reference/glossary',
];
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 0 additions & 3 deletions lib/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,9 @@ export const navigation = [
{
section: "Tools",
children: [
{ title: "Scaffold Starter App", path: "/tools/scaffold" },
{ title: "Hypercerts CLI", path: "/tools/hypercerts-cli" },
{ title: "Agent Skills", path: "/tools/hypercerts-agent-skills" },
{ title: "Hyperindex", path: "/tools/hyperindex" },
{ title: "Hyperscan", path: "/tools/hyperscan" },
{ title: "Hyperboards", path: "/tools/hyperboards" },
{ title: "Labelers", path: "/tools/labelers" },
],
},
Expand Down
2 changes: 1 addition & 1 deletion pages/architecture/account-and-identity.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ See [ePDS (extended PDS)](/architecture/epds) for integration examples, handle m

For scripts, CLI tools, and server-side automation, use app passwords instead of your main password. App passwords are scoped credentials that can be revoked independently.

Create one in your account settings at [certified.app](https://certified.app). Give it a descriptive name (e.g., "CI/CD pipeline" or "Local development"). If a credential is compromised, revoke just that app password — your main account stays secure. The [Hypercerts CLI](/tools/hypercerts-cli) uses app passwords for authentication.
Create one in your account settings at [certified.app](https://certified.app). Give it a descriptive name (e.g., "CI/CD pipeline" or "Local development"). If a credential is compromised, revoke just that app password — your main account stays secure.

{% callout type="warning" %}
Never commit app passwords to version control. Use environment variables or a secrets manager.
Expand Down
4 changes: 1 addition & 3 deletions pages/getting-started/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const { session } = await client.callback(new URLSearchParams(callbackQuery));
const agent = new Agent(session);
```

See the [AT Protocol OAuth documentation](https://atproto.com/specs/oauth) for full details on client metadata, session storage, and keyset configuration. For further info on how to set up OAuth you can check out [AT Protos node.js implementation tutorial](https://atproto.com/guides/oauth-cli-tutorial) or the [scaffold app](/tools/scaffold).
See the [AT Protocol OAuth documentation](https://atproto.com/specs/oauth) for full details on client metadata, session storage, and keyset configuration. For a step-by-step Node.js example, see the [AT Protocol OAuth tutorial](https://atproto.com/guides/oauth-cli-tutorial).

## Create your first hypercert

Expand Down Expand Up @@ -347,8 +347,6 @@ Your hypercert is now created and stored on your PDS. The completion screen show
![Completion screen showing the finished hypercert](/images/scaffold/finalized-cert.png)
*The hypercert is created and stored on your PDS.*

For full details on the Scaffold app — including self-hosting, environment setup, and extending the codebase — see the [Scaffold app documentation](/tools/scaffold).

## Next steps

Third parties can now [evaluate your hypercert](/getting-started/working-with-evaluations) by creating evaluation records and measurements on their own PDS.
1 change: 0 additions & 1 deletion pages/tools/hyperscan.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,4 @@ Use the Agent API when you want a tool, bot, or coding agent to understand the c

- [Hyperindex](/tools/hyperindex) — indexer used to query and serve indexed Hypercerts data
- [Labelers](/tools/labelers) — ATProto label services used for quality and trust signals
- [Hypercerts CLI](/tools/hypercerts-cli) — command-line tool for creating and inspecting Hypercerts records
- [Introduction to Lexicons](/lexicons/introduction-to-lexicons) — schemas behind the records shown in Hyperscan
50 changes: 50 additions & 0 deletions test/hidden-tool-visibility.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const assert = require('node:assert/strict');
const { existsSync, readFileSync, readdirSync } = require('node:fs');
const { join, relative } = require('node:path');
const test = require('node:test');

const ROOT = join(__dirname, '..');
const PAGES_DIR = join(ROOT, 'pages');
const HIDDEN_PATHS = [
'/tools/hypercerts-cli',
'/tools/scaffold',
'/tools/hyperboards',
];
const ROUTE_PAGE_FILES = HIDDEN_PATHS.map((path) => `pages${path}.md`);
const DRAFT_PAGE_FILES = HIDDEN_PATHS.map((path) => `drafts${path}.md`);

function walkMarkdownFiles(directory) {
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const path = join(directory, entry.name);
return entry.isDirectory() ? walkMarkdownFiles(path) : path.endsWith('.md') ? [path] : [];
});
}

test('archives hidden tool pages outside the routable pages directory', () => {
for (const file of ROUTE_PAGE_FILES) {
assert.equal(existsSync(join(ROOT, file)), false, `${file} must not remain routable`);
}
for (const file of DRAFT_PAGE_FILES) {
assert.equal(existsSync(join(ROOT, file)), true, `${file} must preserve the page source`);
}
});

test('does not link to hidden tool pages from visible documentation or navigation', () => {
const authoredFiles = [
join(ROOT, 'components/Layout.js'),
join(ROOT, 'components/SearchDialog.js'),
join(ROOT, 'lib/navigation.js'),
...walkMarkdownFiles(PAGES_DIR),
];

for (const file of authoredFiles) {
const content = readFileSync(file, 'utf8');
for (const path of HIDDEN_PATHS) {
assert.equal(
content.includes(path),
false,
`${relative(ROOT, file)} still links to ${path}`,
);
}
}
});