# FreeRusTOS (FreeRTOS-in-Rust) — AGENTS.md

This file is written for AI coding agents (Codex and others). It defines the *default* working agreements for this repo.

Codex reads `AGENTS.md` files before doing any work and supports layered overrides via `AGENTS.override.md` (see References at the end).

---

## Quick commands (agent workflow)

Prefer these commands when validating changes:

- Format: `cargo fmt`
- Compile-only (early phase): `cargo check --features port-dummy`
- Unit tests (once present): `cargo test --features std,port-dummy`

If embedded targets are configured later, the repo may add target-specific commands.

---

## Mission

Build a **single, monolithic, pure-Rust crate** that is effectively **“FreeRTOS kernel ported to Rust”**.

- Crate nickname: **FreeRusTOS**
- Primary deliverable: a crate you can `cargo add` into a `no_std` embedded project and get an RTOS **without** C FFI and **without** “pthread-on-top” indirection.
- Strategy: **line-by-line, imperative translation** of the FreeRTOS kernel C sources into Rust, staying as close to the original control-flow and data layout as reasonably possible.

### Non-goals (at least initially)

- No “Rust-first redesign” of the API or scheduler internals.
- No attempt to make the core kernel “100% safe Rust” in early phases.
- No dependency-heavy runtime, no OS threads/pthreads as the scheduler.
- No full hardware bring-up in the first iteration (a dummy/empty port is acceptable to begin with).

---

## Upstream baseline and licensing

### Upstream baseline (pin it; do not chase `main`)

Pick a single upstream FreeRTOS-Kernel version and keep it **pinned** as the translation target (tags are preferred).

Recommended starting baseline:
- **FreeRTOS Kernel v11.1.0 (LTS line)**

Notes:
- The FreeRTOS kernel upstream is MIT licensed.
- This repo is a close port / derivative work; keep upstream notices and licensing headers.

---

## Project principles

### 1) “C-shaped Rust”
Prefer Rust that looks like the original C.

- Use `while` loops and explicit indexing over iterator chains.
- Prefer repeated `x = ...;` assignments over clever expressions.
- Avoid “clever” lifetime gymnastics and overly-generic abstractions.
- Prefer direct struct fields over accessor methods, unless necessary.

### 2) Port correctness over idiomaticity
- Maintain **control flow**, **branching**, and **side effects** as close to upstream as possible.
- Do not refactor “for cleanliness” unless required for Rust compilation or to preserve semantics.

### 3) Unsafe is acceptable, but disciplined
- Expect extensive `unsafe` (raw pointers, aliasing, `static mut`, etc.) to mirror C behavior.
- Keep `unsafe` blocks **as small as practical** and put a short comment on *why* it is safe “enough” / equivalent to C.

### 4) Preserve comments with amendments
- Preserve upstream FreeRTOS comments verbatim wherever possible.
- If a comment must change due to Rust differences, keep original text and add an immediate:

  **`[AMENDMENT]`** block explaining what changed and why.

---

## Repository layout (target shape)

A suggested layout that supports line-by-line porting while remaining one crate:

- `src/lib.rs`
  - Crate root; exports the public FreeRTOS-like API modules.
- `src/config.rs`
  - Rust equivalent of `FreeRTOSConfig.h` (constants + feature gates).
- `src/types.rs`
  - Rust equivalents of `BaseType_t`, `UBaseType_t`, `TickType_t`, handles, etc.
- `src/kernel/`
  - “One module per C file” translations:
    - `list.rs`   (from `list.c` + `list.h`)
    - `queue.rs`  (from `queue.c` + `queue.h`)
    - `tasks.rs`  (from `tasks.c` + `task.h`)
    - `timers.rs`, `event_groups.rs`, `stream_buffer.rs`, etc. (later)
- `src/port/`
  - Port layer and architecture hooks:
    - `mod.rs` selects the active port via `cfg(feature = "...")`
    - `dummy.rs` is the initial empty port used for compilation
- `src/memory/`
  - `pvPortMalloc`, `vPortFree`, plus optional heap implementations later.
- `upstream/` (reference only; not compiled)
  - Vendored snapshot or submodule of upstream FreeRTOS-Kernel for side-by-side comparison.
  - Keep this out of published crate artifacts via `Cargo.toml` `exclude = [...]`.

---

## Build modes and the “dummy port” strategy

We need a build that compiles early, before real context-switching exists.

### Required initial build target

- The kernel modules must **compile** with a **dummy** port and dummy interrupt primitives.
- Link success is optional in the earliest stage, but compilation must be reliable.

### Dummy port requirements

Provide stub implementations for:
- critical sections (`enter/exit critical`)
- interrupt enable/disable
- yield / context switch trigger
- tick source setup (stubbed)
- scheduler start/stop hooks
- stack initialization routine (can be a placeholder returning the input pointer)

The dummy port may:
- `panic!()` / `todo!()` at runtime
- return conservative defaults
- be gated behind `feature = "port-dummy"` (enabled by default during early work)

---

## Configuration strategy (replacing `FreeRTOSConfig.h`)

### Goal
Replace FreeRTOS preprocessor config macros with a Rust configuration layer that is:
- simple,
- explicit,
- and keeps the kernel translation readable.

### Rules
- Mirror upstream config names conceptually (e.g., `configUSE_PREEMPTION`).
- Prefer `const` values in `config.rs` for numeric constants.
- Prefer `cfg(feature = "...")` for major feature toggles.
- Avoid dynamic configuration initially.

### Compatibility shim
When the translated C expects macro-like forms, provide a small shim layer:
- `#[inline(always)]` functions for “function-like macros”
- `macro_rules!` only when the C macro relies on expression substitution or statement blocks.

---

## Macro translation policy

FreeRTOS uses many macros for:
- tracing hooks,
- critical sections,
- list ops,
- asserts,
- and configuration gates.

Policy:
1. **First choice:** `#[inline(always)] fn` (simple, readable, debuggable).
2. **Second choice:** `macro_rules!` (only when necessary to preserve semantics).
3. **Avoid:** complicated “metaprogramming” macros.

When macros map to hooks (trace, coverage, app hooks), make them:
- no-ops by default
- enableable by feature flags
- callable from the same locations as upstream

---

## Memory allocation strategy

FreeRTOS kernel expects:
- `pvPortMalloc` / `vPortFree`
- optional heap implementations (heap_1..heap_5)

Incremental plan:
1. **Phase 1 (compile-first):**
   - Implement `pvPortMalloc`/`vPortFree` as thin wrappers around Rust’s global allocator **when `alloc` is enabled**.
   - If `alloc` is not enabled, allow stubs that compile but panic at runtime.
2. **Phase 2 (functional):**
   - Add a minimal, deterministic allocator (bump or linked-list) behind a feature.
3. **Phase 3 (FreeRTOS parity):**
   - Port `heap_4` and/or `heap_5` to Rust as optional modules.

Do not add external allocator crates unless absolutely necessary and explicitly justified (keep dependencies minimal).

---

## Testing strategy (how we “eat the elephant”)

### Unit tests
Use host tests to validate internal invariants:
- list operations (`vListInitialise`, insert/remove, ownership)
- queue bookkeeping (creation, send/receive state transitions)
- scheduler-ready lists logic (later)

Because `no_std` complicates tests:
- It is acceptable to enable `std` only under `#[cfg(test)]` or a `feature = "std"`.

### Incremental compile gates
Each port step must keep the crate compiling:
- `cargo check` should pass after each file/module landing.
- Prefer “compile scaffolding” (stubs) over partially-written logic that breaks the build.

---

## Naming and public API policy

- Keep upstream FreeRTOS function names (e.g., `xTaskCreate`, `vTaskDelay`) to reduce cognitive load and simplify diffs.
- Permit non-idiomatic casing; use module-level `#[allow(non_snake_case, non_camel_case_types)]` where needed.
- Public API should initially match FreeRTOS as closely as feasible; “Rusty wrappers” can come later.

---

## Change discipline and review checklist

When changing or adding code:
- Keep diffs small and localized (one module/function at a time).
- Maintain the “C-shaped Rust” style.
- Preserve comments; add `[AMENDMENT]` only where required.
- If you must deviate from upstream behavior, document it in-code and in a short note in the PR/commit message.

Recommended local checks:
- `cargo fmt`
- `cargo check --features port-dummy`
- `cargo test --features std,port-dummy` (when tests exist)

---

## Suggested milestones

1. **M0 — Skeleton compiles**
   - Crate compiles with `port-dummy`
   - types/config scaffolding exists

2. **M1 — Port `list`**
   - `list.rs` compiles
   - unit tests cover core list behavior

3. **M2 — Port `queue`**
   - `queue.rs` compiles
   - basic queue tests (no real blocking yet)

4. **M3 — Port `tasks` (compile-first)**
   - `tasks.rs` compiles
   - scheduler structures exist, even if non-functional

5. **M4 — Minimal scheduler start path**
   - `vTaskStartScheduler` path compiles end-to-end
   - dummy port still allowed to panic at runtime

6. **M5 — First real embedded port**
   - pick one architecture (e.g., Cortex-M) and implement the true port layer

---

## References

- OpenAI Codex docs: Custom instructions with AGENTS.md
  https://developers.openai.com/codex/guides/agents-md/

- OpenAI blog: Introducing Codex (mentions AGENTS.md guidance)
  https://openai.com/index/introducing-codex/

- FreeRTOS licensing (kernel is MIT)
  https://www.freertos.org/libraries/license.html

- FreeRTOS LTS libraries (kernel LTS status)
  https://freertos.org/lts-libraries.html
