Skip to content
Draft
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
3 changes: 0 additions & 3 deletions .codex/config.toml

This file was deleted.

File renamed without changes.
6 changes: 3 additions & 3 deletions CONTRIBUTING.md → .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ Hyperkernel requires Node.js 24 or later and npm 11 or later.

```sh
npm ci
cp .env.example .env
cp apps/playground/.env.example apps/playground/.env
npm run dev
```

The default SQLite database is `./local.db`. Local database files and `.env`
files are ignored by Git.
The default SQLite database is `apps/playground/local.db`. Local database files
and `.env` files are ignored by Git.

## Verification

Expand Down
File renamed without changes.
22 changes: 1 addition & 21 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
# macOS
node_modules/
.DS_Store

# Env
.env
.env.*
!.env.example
!.env.test

# SQLite
*.db

# Node.js
/node_modules

# SvelteKit
/.svelte-kit
/build

# Playwright
/.playwright-mcp
/test-results
1 change: 0 additions & 1 deletion .husky/pre-commit

This file was deleted.

8 changes: 0 additions & 8 deletions .mcp.json

This file was deleted.

1 change: 0 additions & 1 deletion .prettierignore

This file was deleted.

7 changes: 0 additions & 7 deletions .vscode/mcp.json

This file was deleted.

29 changes: 22 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,39 @@ Hyperkernel currently requires Node.js 24 or later and npm 11 or later.

## Repository boundaries

- `src/routes/` contains SvelteKit routes and transport/UI entry points.
- `src/lib/server/db/index.ts` owns the shared `DatabaseSync` connection.
- `src/lib/server/` is server-only and must never be imported by client code.
- `src/lib/components/` contains reusable interface components.
- `apps/playground/` contains the private example application that developers
use to learn and experiment with Hyperkernel.
- `apps/playground/src/routes/` contains SvelteKit routes and transport/UI entry
points.
- `apps/playground/src/lib/server/db/index.ts` owns the shared `DatabaseSync`
connection for the playground.
- `apps/playground/src/lib/server/` is server-only and must never be imported by
client code.
- `packages/ui/src/` contains reusable interface components exported through
`@hyperkernel/ui`.
- `docs/adr/` contains architecture decision records for repository-wide architecture and governance definitions.
- `docs/design/` contains numbered design records for significant contracts and decisions.
- `docs/spikes/` contains isolated architecture experiments. Spikes are not production modules, supported APIs, or proof that a contract is implemented.

Keep database connection creation centralized in `src/lib/server/db/index.ts`. Use the built-in `node:sqlite` module. Do not introduce an ORM, another SQLite client, a second ad hoc connection, or direct database access outside the server boundary unless an intentional architecture change is documented and approved.
Keep database connection creation centralized in
`apps/playground/src/lib/server/db/index.ts`. Use the built-in `node:sqlite`
module. Do not introduce an ORM, another SQLite client, a second ad hoc
connection, or direct database access outside the server boundary unless an
intentional architecture change is documented and approved.

Framework transports must be adapters around the command/query contracts. Do not make the kernel depend on SvelteKit request objects, remote-function internals, or UI component state.

## Svelte and interface guidance

- Use Svelte 5 runes for application code.
- Experimental SvelteKit remote-function support is enabled in `vite.config.ts`; it may be used for RPC-style flows, but authoritative command, event, and projection contracts must remain framework-independent.
- Experimental SvelteKit remote-function support is enabled in
`apps/playground/vite.config.ts`; it may be used for RPC-style flows, but
authoritative command, event, and projection contracts must remain
framework-independent.
- Use native CSS in scoped Svelte `<style>` blocks for component and page styling.
- Keep the bootstrap document reset in `src/app.html` minimal. Put other document-level rules in the root layout with `:global`; keep theme tokens owned by the theme boundary.
- Inter is imported in `src/routes/+layout.svelte`. Reuse the existing font token rather than adding component-specific font stacks.
- Inter is imported in `apps/playground/src/routes/+layout.svelte`. Reuse the
existing font token rather than adding component-specific font stacks.
- Prefer modern HTML and Web Platform primitives such as `<dialog>`, the Popover API, `<details>`, native form controls, and the Clipboard API. Do not introduce a headless UI library without an explicit architecture decision.
- Preserve native keyboard, focus, and accessibility semantics.
- Treat excellent developer experience, a friendly user experience, and persistent multitasking as product requirements.
Expand All @@ -224,6 +238,7 @@ Infer TypeScript types from Zod schemas instead of duplicating manual interfaces
- Prefer domain names over generic names such as `data`, `item`, `handler`, `manager`, `helper`, or `utils`.
- Prefer standard ECMAScript, Web Platform, Svelte, SvelteKit, and CSS APIs over project-specific wrappers.
- Do not extract a one-use helper unless it creates a real boundary, names a domain invariant, or materially reduces complexity.
- Do not introduce a one-use local merely to restate a short, readable expression. Keep a local when it names a domain concept or boundary, avoids repeated or side-effectful evaluation, enables type narrowing or cleanup, or materially improves readability.
- Avoid unrelated renaming, formatting, file movement, or refactoring.
- Preserve public contracts unless the task explicitly changes them.
- Separate verified implementation from target architecture in code comments and documentation.
Expand Down
33 changes: 0 additions & 33 deletions CONTEXT.md

This file was deleted.

File renamed without changes.
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Hyperkernel is building a self-hostable platform for connected applications that developers can inspect, trust, and operate themselves. It is designed to provide shared primitives for identity, data, permissions, and app-to-app communication, so independently developed applications can work together without giving up reliability, auditability, or control.

> [!NOTE]
> Hyperkernel is currently in the design phase. The repository contains an early SvelteKit shell and a centralized SQLite connection, but almost none of the platform described here is implemented; the first version is under active development. Until that version is stable, this document describes the intended architecture. It will then be revised to reflect the implemented system.
> Hyperkernel is currently in the design phase. The repository contains an early SvelteKit example application and a centralized SQLite connection, but almost none of the platform described here is implemented; the first version is under active development. Until that version is stable, this document describes the intended architecture. It will then be revised to reflect the implemented system.

The architecture separates software into two trust zones:

Expand Down Expand Up @@ -124,13 +124,21 @@ Hyperkernel is an early architecture prototype. This document defines the target

The repository currently contains:

- an early SvelteKit application shell with a Node.js adapter;
- an early SvelteKit example application under `apps/playground` with a Node.js
adapter;
- a centralized server-only SQLite connection using the built-in `node:sqlite` module;
- formatting, type-checking, unit-test, browser-test, build, and CI tooling;
- an isolated event-sourcing and projection spike under `docs/spikes/`.

Commands, the production event store, event versioning, replay, projection rebuilds, time travel, permissions, the public SDK, persistent multitasking, and external agent execution are not implemented yet.

### Playground

`apps/playground` is the example application for developers to learn how
Hyperkernel packages fit together and to experiment with using the platform.
It is a private npm workspace, not a production-ready application or a
supported public package.

## First milestone

The first milestone is a complete, small vertical slice that proves:
Expand All @@ -150,7 +158,7 @@ Hyperkernel requires Node.js 24 or later and npm 11 or later.

```sh
npm ci
cp .env.example .env
cp apps/playground/.env.example apps/playground/.env
npm run dev
```

Expand All @@ -175,7 +183,10 @@ npm run build
npm start
```

`DATABASE_URL` configures the SQLite connection path. The repository does not yet contain a production event schema, migrations, backup and restore guarantees, or an upgrade contract.
`DATABASE_URL` configures the SQLite connection path relative to
`apps/playground` unless it is absolute. The repository does not yet contain a
production event schema, migrations, backup and restore guarantees, or an
upgrade contract.

## Contributing

Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions apps/playground/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.svelte-kit/
build/
30 changes: 30 additions & 0 deletions apps/playground/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@hyperkernel/playground",
"version": "0.0.1",
"private": true,
"description": "Example application for learning and experimenting with Hyperkernel.",
"license": "MIT",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check"
},
"dependencies": {
"@fontsource-variable/inter": "^5.3.0",
"@hyperkernel/sqlite": "^0.0.1",
"@hyperkernel/ui": "^0.0.1",
"zod": "^4.4.3"
},
"devDependencies": {
"@sveltejs/adapter-node": "^5.5.7",
"@sveltejs/kit": "^2.70.1",
"@sveltejs/vite-plugin-svelte": "^7.2.0",
"@types/node": "^26.1.2",
"svelte": "^5.56.8",
"svelte-check": "^4.7.4",
"typescript": "^6.0.3",
"vite": "^8.1.5"
}
}
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions apps/playground/src/lib/server/db/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { openDatabase } from "@hyperkernel/sqlite";
import { env } from "$env/dynamic/private";

export const db = openDatabase(env.DATABASE_URL);
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import "@fontsource-variable/inter/wght-italic.css";

import favicon from "$lib/assets/favicon.svg";

import Theme from "$lib/components/Theme.svelte";
import { Theme } from "@hyperkernel/ui";

let { children } = $props();
</script>
Expand Down
9 changes: 9 additions & 0 deletions apps/playground/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import { Canvas, Paragraph, Window } from "@hyperkernel/ui";
</script>

<Canvas>
<Window title="Documents">
<Paragraph>No documents found</Paragraph>
</Window>
</Canvas>
3 changes: 1 addition & 2 deletions tsconfig.json → apps/playground/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"types": ["node"],
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"rewriteRelativeImportExtensions": true
"esModuleInterop": true
}
}
15 changes: 15 additions & 0 deletions apps/playground/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from "vite";
import { sveltekit } from "@sveltejs/kit/vite";
import adapter from "@sveltejs/adapter-node";

export default defineConfig({
plugins: [
sveltekit({
compilerOptions: {
runes: ({ filename }) =>
filename.split(/[/\\]/).includes("node_modules") ? undefined : true,
},
adapter: adapter(),
}),
],
});
91 changes: 91 additions & 0 deletions docs/adr/0002-path-and-pathname-terminology.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# ADR 0002: Path and pathname terminology

| Field | Value |
| ------------ | ----------------------------- |
| Status | Stable |
| Scope | Kernel, Extension, Experience |
| Created | 2026-07-27 |
| Last updated | 2026-07-27 |

## Summary

Hyperkernel uses `path` for a general location accepted by an API, and
`pathname` only for the path component of a URL. The two names are not
interchangeable.

## Problem

Location-like inputs can be filesystem paths, opaque identifiers accepted by an
API, complete URLs, or one component of a URL. Calling each of them `path` or
`pathname` without a rule makes public APIs harder to understand and obscures
what inputs they accept.

## Decision

Use `path` when an API accepts a general location. It may be a filesystem path,
an opaque location syntax documented by that API, or a complete `URL` when the
underlying API accepts one.

```ts
const configurationPath = "./config/hyperkernel.json";
const memoryPath = ":memory:";
declare const resourcePath: URL;
```

Use `pathname` only when referring to the pathname component of a URL. It is a
string such as `/workspaces/acme`, not the complete URL.

```ts
const url = new URL("https://example.test/workspaces/acme?tab=events");

url.pathname; // "/workspaces/acme"
url.href; // "https://example.test/workspaces/acme?tab=events"
```

Use `url` when an API specifically requires a complete URL and does not accept
another kind of location.

```ts
function redirect(url: URL): Response {
return Response.redirect(url);
}
```

This ADR governs names in programmatic APIs, configuration fields, types, and
developer documentation. It does not prohibit ordinary prose such as "command
execution path" where no location value is being named.

## Examples

| Value or concept | Name | Reason |
| ---------------------------------------------------------------------- | ---------- | -------------------------------------------------------------- |
| `./config/hyperkernel.json` supplied to a configuration reader | `path` | It is a filesystem location. |
| `:memory:` supplied to a storage API | `path` | It is an API-specific location, not a URL pathname. |
| `new URL("file:///var/lib/hyperkernel.db")` supplied to a resource API | `path` | The receiving API accepts a general location, including a URL. |
| `/projects/hyperkernel` from `new URL(...).pathname` | `pathname` | It is precisely the URL pathname component. |
| `https://example.test/projects/hyperkernel?view=events` | `url` | The complete URL includes origin and query string. |
| A route matcher input derived from `request.url` | `pathname` | Routing commonly operates on only the URL pathname. |

## Alternatives considered

### Use `path` for every location-like value

Rejected. It would obscure whether a value is a complete URL or only its path
component.

### Use `pathname` for all path values

Rejected. `pathname` has a precise URL-specific meaning and does not describe
filesystem paths or API-specific location syntax.

## Consequences

API names communicate valid input shapes without relying on implementation
knowledge. A `pathname` must never be documented as a complete URL, and a
`path` must not be assumed to be a URL pathname.

## Status history

| Date | Status | Note |
| ---------- | ------ | ------------------------------------------------------ |
| 2026-07-27 | Stable | Global terminology chosen for current and future APIs. |
Loading
Loading