Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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 .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Skills are short. If a skill needs more than ~200 lines, either (a) the underlyi
| [update-glossary](update-glossary/SKILL.md) | Add or update an entry in the glossary. |
| [sync-adr-index](sync-adr-index/SKILL.md) | Rebuild the ADR index table from the files on disk. |
| [start-task](start-task/SKILL.md) | Open a new roadmap task from the user-story template. |
| [conduct-review](conduct-review/SKILL.md) | Produce a milestone retrospective in `docs/roadmap/reviews/`. |
| [conduct-review](conduct-review/SKILL.md) | Produce a business / code / security / performance review artifact in `docs/analysis/reviews/<type>-reviews/`. |
| [add-bsp](add-bsp/SKILL.md) | Add a new Board Support Package crate — crate skeleton, boot checklist, console, context switch, smoke test. |

## Conventions for adding a new skill
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/add-bsp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ when-to-use: When adding support for a new hardware target (e.g. Raspberry Pi 4,

# Add BSP

> **Length note.** This skill intentionally exceeds the ~200-line soft limit in [the skills README](../README.md). Bringing up a new board is irreducibly long — the `boot.s` template (step 4) and the smoke-test diagnostic table (step 10) are load-bearing checklist content, not padding, and a partial procedure here would be more dangerous than a long one. Kept whole rather than split or moved to a guide.

## Inputs

Before starting, the agent must have:
Expand Down
169 changes: 130 additions & 39 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,26 @@
#
# Goal: every hygiene check that a contributor is expected to pass
# locally before opening a PR is also enforced here. A red CI blocks
# merge. The Miri and coverage jobs are slower and run conditionally
# to keep median PR feedback tight; they are still required for merge
# into `main`.
# merge.
#
# What actually gates merge (configured in GitHub branch protection):
# - lint-and-host-test, kernel-build, host-stable-check (fast lane)
# - miri (required, slow)
# The `miri` job runs the host-test suite under Stacked Borrows; it is
# slower (~10–15 min) but a Miri regression is a hard stop. The
# `coverage` job is INFORMATIONAL only (it sets `continue-on-error: true`)
# and must NOT be added to the required-checks list until the post-T-011
# flip removes that flag — see docs/guides/ci.md §"Branch protection".
#
# Toolchain note: the kernel needs nightly (inline asm / lang items),
# so the lint-and-host-test, kernel-build, and miri jobs all run the
# pinned nightly ($NIGHTLY_PIN) — the same toolchain rust-toolchain.toml
# selects for in-repo `cargo` invocations. A separate host-stable-check
# job gives a genuine "host crates build clean on stable" signal.
#
# When this pipeline was born (2026-04-23, R6 retrospective work) the
# local host-test count was 111; the kernel-build target was
# aarch64-unknown-none. Any time a new crate or target lands, update
# the job matrix below.
# kernel-build target was aarch64-unknown-none. Any time a new crate or
# target lands, update the job matrix below.

name: CI

Expand All @@ -25,10 +37,23 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

# Least-privilege for the auto-provisioned GITHUB_TOKEN. This pipeline
# only reads the repository and runs builds; it never writes refs,
# publishes artifacts, or touches issues/PRs. Override per-job only if a
# future job genuinely needs more — none do today.
permissions:
contents: read

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -D warnings
# Pinned nightly for miri + coverage jobs. Rolling nightly means a
# NOTE: `-D warnings` is intentionally NOT set as a global RUSTFLAGS env
# var. A process-wide RUSTFLAGS REPLACES (does not merge) the per-target
# `[target.aarch64-unknown-none] rustflags` in .cargo/config.toml, which
# would silently drop `panic=abort` + `force-frame-pointers=yes` from the
# kernel build — CI would then compile a different ELF than a local build.
# Deny-warnings is enforced instead by the `-- -D warnings` already passed
# in the host-clippy / kernel-clippy aliases (.cargo/config.toml).
# Pinned nightly for the kernel + miri + coverage jobs. Rolling nightly means a
# miri/llvm-tools regression on the public channel breaks master
# without any commit of ours being the cause. Update this pin
# intentionally (open an issue citing the pin bump), not silently.
Expand All @@ -37,67 +62,122 @@ env:
NIGHTLY_PIN: nightly-2026-01-15

jobs:
# ─── Fast lane: lint + host tests on stable ─────────────────────────────
# ─── Fast lane: fmt + clippy + host tests (pinned nightly) ──────────────
# Expected wall time: ~2 min. Every PR must pass this before anything
# else runs.
# else runs. Runs on the pinned nightly — `rust-toolchain.toml` overrides
# `rustup default` for in-repo cargo anyway, so we select the pin
# explicitly (matching the miri/coverage jobs) instead of pretending to
# run on stable. A genuine stable signal lives in `host-stable-check`.
lint-and-host-test:
name: fmt + clippy + host tests
name: fmt + clippy + host tests (nightly)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable with rustfmt + clippy
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Comment thread
coderabbitai[bot] marked this conversation as resolved.
with:
# CI only reads the repo; do not persist the token into local git
# config (least-privilege; avoids credential reuse by later steps).
persist-credentials: false
- name: Install pinned nightly with rustfmt + clippy
run: |
rustup update stable --no-self-update
rustup default stable
rustup component add rustfmt clippy
rustup toolchain install $NIGHTLY_PIN --component rustfmt --component clippy --no-self-update
rustup override set $NIGHTLY_PIN
- name: Cache cargo registry and build
uses: actions/cache@v4
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/bin
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-${{ env.NIGHTLY_PIN }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
${{ runner.os }}-cargo-${{ env.NIGHTLY_PIN }}-
- name: cargo fmt --check
run: cargo fmt --all -- --check
run: cargo +$NIGHTLY_PIN fmt --all -- --check
- name: cargo host-clippy
run: cargo host-clippy
run: cargo +$NIGHTLY_PIN host-clippy
- name: cargo host-test
run: cargo host-test
run: cargo +$NIGHTLY_PIN host-test

# ─── Kernel build: aarch64-unknown-none ─────────────────────────────────
# The bare-metal BSP cannot be built as part of the default workspace
# test target (no_std + no_main). Build it explicitly here so the
# kernel ELF and its dependencies stay compilable.
kernel-build:
name: aarch64-unknown-none kernel build
name: aarch64-unknown-none kernel build (nightly)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable + aarch64 target
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# CI only reads the repo; do not persist the token into local git
# config (least-privilege; avoids credential reuse by later steps).
persist-credentials: false
- name: Install pinned nightly + aarch64 target
run: |
rustup update stable --no-self-update
rustup default stable
rustup target add aarch64-unknown-none
rustup component add clippy
rustup toolchain install $NIGHTLY_PIN --component clippy --no-self-update
rustup override set $NIGHTLY_PIN
rustup target add aarch64-unknown-none --toolchain $NIGHTLY_PIN
- name: Cache cargo registry and build
uses: actions/cache@v4
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/bin
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-aarch64-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-aarch64-${{ env.NIGHTLY_PIN }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-aarch64-
${{ runner.os }}-cargo-aarch64-${{ env.NIGHTLY_PIN }}-
- name: cargo kernel-build
run: cargo kernel-build
run: cargo +$NIGHTLY_PIN kernel-build
- name: cargo kernel-clippy
run: cargo kernel-clippy
run: cargo +$NIGHTLY_PIN kernel-clippy

# ─── Host stable check: host crates compile + test on stable ────────────
# A genuine "the host-buildable crates compile and pass tests on stable
# Rust" gate. The kernel image itself needs nightly (inline asm / lang
# items) so the bare-metal BSP is NOT built here — this job runs only the
# workspace default-members (kernel, hal, test-hal), which carry no
# nightly-only features today. If a host crate ever grows a `#![feature]`,
# this job is the one that will (correctly) go red on stable.
#
# Deliberately build + test only — NOT clippy/fmt with `-D warnings`.
# `clippy::pedantic` is `warn` workspace-wide and stable is a rolling
# toolchain: a future stable release can add a pedantic lint that turns a
# `-D warnings` gate red with no code change of ours. Lint/format
# enforcement therefore lives only on the pinned-nightly jobs (which run
# host-clippy + fmt), keeping this gate immune to upstream lint drift.
host-stable-check:
name: host crates on stable
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# CI only reads the repo; do not persist the token into local git
# config (least-privilege; avoids credential reuse by later steps).
persist-credentials: false
- name: Install Rust stable
run: |
rustup toolchain install stable --no-self-update
- name: Cache cargo registry and build
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/bin
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-stable-
# Explicit `+stable` bypasses the rust-toolchain.toml override so this
# job exercises stable for real. `cargo build` / `host-test` operate on
# default-members (host-buildable crates only); the bare-metal BSP is
# never built here. No `-D warnings` lint/fmt step — see the job header.
- name: cargo +stable build (host crates)
run: cargo +stable build
- name: cargo +stable host-test
run: cargo +stable host-test

# ─── Miri: aliasing validation ──────────────────────────────────────────
# Runs the full host-test suite under Miri's Stacked Borrows checker
Expand All @@ -108,13 +188,17 @@ jobs:
name: miri (Stacked Borrows)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# CI only reads the repo; do not persist the token into local git
# config (least-privilege; avoids credential reuse by later steps).
persist-credentials: false
- name: Install pinned nightly with miri
run: |
rustup toolchain install $NIGHTLY_PIN --component miri --no-self-update
rustup override set $NIGHTLY_PIN
- name: Cache cargo registry and miri target
uses: actions/cache@v4
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/bin
Expand All @@ -139,7 +223,11 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# CI only reads the repo; do not persist the token into local git
# config (least-privilege; avoids credential reuse by later steps).
persist-credentials: false
- name: Install pinned nightly with llvm-tools
run: |
rustup toolchain install $NIGHTLY_PIN --component llvm-tools-preview --no-self-update
Expand All @@ -155,12 +243,15 @@ jobs:
# The cargo-llvm-cov version pin is independent of NIGHTLY_PIN —
# the two can be bumped together or independently per
# docs/guides/ci.md "Nightly pinning".
uses: taiki-e/install-action@v2
uses: taiki-e/install-action@e0eafa9a0d485c37f97c0f7beb930a58a2facbac # v2.79.4
with:
tool: cargo-llvm-cov@0.6.16
- name: Cache cargo registry and llvm-cov target
uses: actions/cache@v4
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
# ~/.cargo/bin is intentionally omitted here (unlike the sibling
# jobs): cargo-llvm-cov is installed by taiki-e/install-action, not
# `cargo install`, so nothing useful lands in ~/.cargo/bin to cache.
path: |
~/.cargo/registry
~/.cargo/git
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ tmp/
.tmp/

# Claude Code runtime state — per-session lock files coordinating tools like
# ScheduleWakeup. The .claude/skills/ tree itself IS tracked (project skills
# are source of truth); only runtime lock files are ignored.
# ScheduleWakeup. Only runtime lock files under .claude/ are ignored; the
# tracked project skills live under .agents/skills/ (migrated from
# .claude/skills/ on 2026-05-14) and are committed as the source of truth.
.claude/*.lock

# Python tooling occasionally used for build scripts
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file is the entry point for Claude-based AI agents (Claude Code, Claude API

## What this project is

Tyrne is a **capability-based microkernel** written in Rust, in the lineage of seL4 and Hubris. The project is **pre-alpha** — most code is not yet written, and the current phase is architecture design captured in Architecture Decision Records (ADRs). Primary development target is QEMU `virt` on aarch64; first real hardware target is the Raspberry Pi 4.
Tyrne is a **capability-based microkernel** written in Rust, in the lineage of seL4 and Hubris. The project is **pre-alpha**, but implementation is well underway: the kernel boots end-to-end on QEMU `virt` aarch64 and runs a two-task capability-gated IPC demo. The project is **mid-Phase B** — the MMU, PMM, address-space objects, and task loader (load half) are done; the syscall ABI and first userspace task are next. Architecture is documented as Architecture Decision Records (see the [ADR index](docs/decisions/README.md)); active implementation work lives under `kernel/`, `hal/`, and `bsp-qemu-virt/`. Primary development target is QEMU `virt` on aarch64; first real hardware target is the Raspberry Pi 4.

See [README.md](README.md) for the public overview.

Expand All @@ -13,7 +13,7 @@ See [README.md](README.md) for the public overview.
These rules apply to every AI agent acting inside this repository, regardless of model, runner, or tool.

1. **Security-first mindset.** Tyrne is built to be a high-assurance OS. When in doubt, choose the more conservative option. Never weaken a capability check, never introduce ambient authority, never suppress a failing security test.
2. **Memory safety through Rust.** All kernel and userspace code is Rust. Every `unsafe` block must have a comment explaining (a) why it is needed, (b) what invariants it upholds, (c) why safer alternatives were rejected. Audit tracking for `unsafe` is defined in [docs/standards/](docs/standards/).
2. **Memory safety through Rust.** All kernel and userspace code is Rust. Every `unsafe` block must have a comment explaining (a) why it is needed, (b) what invariants it upholds, (c) why safer alternatives were rejected. The `unsafe` policy is in [docs/standards/unsafe-policy.md](docs/standards/unsafe-policy.md); each block's audit entry lives in the log at [docs/audits/unsafe-log.md](docs/audits/unsafe-log.md).
3. **English in the repository.** Source code, comments, doc-comments, documentation, commit messages, PR descriptions, issue text, and this file are English. Conversation with the maintainer in chat may be Turkish, but nothing committed to the repo should be.
4. **Mermaid for diagrams.** All architectural diagrams are inline Mermaid code fences. Do not add PNG, SVG, ASCII-art, or other binary diagram formats.
5. **Record decisions as ADRs.** Any non-trivial architectural, security, or process decision is recorded as an ADR in [docs/decisions/](docs/decisions/) using the MADR template. ADRs are append-only; to override an old decision, write a new ADR that supersedes it.
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to Tyrne

Thank you for your interest. Tyrne is currently in the **architecture phase** — the foundational design documents are being written and the codebase is not yet open for code contributions.
Thank you for your interest. Tyrne is **pre-alpha** and mid-way through Phase B: the Rust workspace exists, the kernel boots end-to-end on QEMU `virt` aarch64, and it runs a two-task IPC demo. Implementation is active, but the codebase is not yet open for unsolicited code contributions — each subsystem is being grown along the phased roadmap, and changes outside the active milestone's scope force premature rewrites. Issues, references, and ADR review are very welcome (see below).

## What is useful right now

Expand All @@ -11,7 +11,7 @@ Thank you for your interest. Tyrne is currently in the **architecture phase**

## What is not useful yet

- Pull requests against source code outside the active milestone scope. The Rust workspace exists and the kernel boots end-to-end on QEMU virt (Phase A + B0/B1 closed), but each subsystem is being grown along the phased roadmap in [`docs/roadmap/`](docs/roadmap/); changes outside the current milestone's scope force premature rewrites and are usually not merged. Check [`docs/roadmap/current.md`](docs/roadmap/current.md) before opening a non-trivial PR.
- Pull requests against source code outside the active milestone scope. The Rust workspace exists and the kernel boots end-to-end on QEMU virt (Phase A and milestones B0–B3 closed; B4 active), but each subsystem is being grown along the phased roadmap in [`docs/roadmap/`](docs/roadmap/); changes outside the current milestone's scope force premature rewrites and are usually not merged. Check [`docs/roadmap/current.md`](docs/roadmap/current.md) before opening a non-trivial PR.
- Feature requests for subsystems that have not yet been designed. File those as discussion issues if you want to influence the design, not as feature requests.

## When the project enters the implementation phase
Expand Down
Loading
Loading