Skip to content

Commit 90793ea

Browse files
docs: add INSTALL.md and align README for main; rustfmt workspace
- INSTALL.md: install-from-source + CI-parity verification checklist - README/CONTRIBUTING: main green policy, INSTALL link, repo layout - CHANGELOG: INSTALL entry; dedupe Unreleased Added section - rustfmt across touched crates Signed-off-by: Gnani Rahul <89947795+gnanirahulnutakki@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 6ba945f commit 90793ea

23 files changed

Lines changed: 346 additions & 199 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
88

99
### Added
1010

11+
- **[INSTALL.md](INSTALL.md)** at repository root: install-from-source steps and the full verification checklist aligned with CI (format, clippy, tests, schema gate, open-verification SHA256, optional Hugo).
12+
1113
- **M0**: Workspace bootstrap, Apache 2.0 licensing, governance documents, planning encyclopedia under `plans/` (48 documents covering landscape, gaps, value proposition, implementation, evaluation, deployment blueprints, and per-runtime quickstarts).
1214
- **M1**: Canonical event schema aligned with OpenTelemetry `gen_ai.*` semconv in `mara-schema`. Adapter/Sink/Policy trait surfaces in `mara-core`. Seven Architecture Decision Records covering license, WASM policy host, WAL format, hot reload, async runtime, error model, and configuration format.
1315
- **M2**: Pipeline scheduler (adapters → policy chain → sinks fan-out) in `mara-core::pipeline`. TOML configuration loader with JSON-schema-style validation in `mara-core::config`. JSONL tail adapter with per-file offset checkpointing. File rotation sink and stdout sink. Built-in PII redaction policy (regex-based, covering email, US phone, SSN, AWS / GCP / GitHub / OpenAI / Anthropic / Slack tokens, JWT). Head sampling policy. CLI `mara run`, `mara validate`, `mara version`, `mara setup <preset>` (stub) wired against config files. End-to-end integration test: JSONL → PII redaction → file sink.
@@ -20,17 +22,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
2022
- **CI / M2-02**: `scripts/benchmarks/schema_completeness_gate.py` plus job `schema-completeness-gate` — at least three runtime fixtures must average ≥85% fill on seven required `gen_ai`/`resource` fields.
2123
- **M2 (milestone board)**: Agent fields on `MaraExtensions`, gateway correlation id (`x-mara-request-id` / `mara.request_id`), dual latency metrics (gateway vs engine), `CostConfidence` for honest cost, parallel sink fan-out, `/readyz` readiness, bounded `/metrics` rendering, fan-out and sink-send-error counters, optional `server.metrics_max_in_flight_connections`, `docs/semconv.lock` + CI drift script, quickstarts, Kubernetes probe fragment, Phoenix/Presidio/eval OTLP notes, single-upstream proxy doc, vector/GPU spike ADR, Grafana compare-by-pipeline panel, and `scripts/materialize_agent_run_summary.py`.
2224
- **Docs / CI**: Redacted Ollama+Mara live-run bundles in `docs/captured/open-verification/` (SHA256 manifest + `scripts/captured/verify_open_verification.sh`; CI job `open-verification-sha256`).
25+
- Per-pipeline **`audit_policy_drops`** (default `false`): when enabled, a minimal `System` audit event (no body; correlation + `mara.policy_audit.*` + policy decisions) is sent to sinks on every policy drop. See `docs/observability/mara-policy-drop-audit.md`.
2326

2427
### Changed
2528

2629
- **Breaking (policy authors)**: `PolicyOutcome::Drop` now includes the dropped `Event`. Use `PolicyOutcome::drop(event, reason)` instead of `PolicyOutcome::drop(reason)`. `ChainOutcome::Drop` is now `{ reason, event }` instead of a bare `String`.
2730
- **`/readyz` readiness**: `Health::is_aggregate_ready` is true only for `healthy` or `degraded` (not `starting`, `stopping`, `stopped`, or `failed`). `Adapter::health` / `Sink::health` default to `Health::healthy()` so typical pipelines stay ready unless an implementation opts into finer-grained status. See `docs/observability/mara-readyz-semantics.md`.
2831
- **LLM proxy**: Response `x-mara-request-id` is always a header-safe value (ASCII fast path, stripped graphic ASCII fallback, or UUID) while events keep the logical correlation id from the client or minted UUID.
2932

30-
### Added
31-
32-
- Per-pipeline **`audit_policy_drops`** (default `false`): when enabled, a minimal `System` audit event (no body; correlation + `mara.policy_audit.*` + policy decisions) is sent to sinks on every policy drop. See `docs/observability/mara-policy-drop-audit.md`.
33-
3433
### Known gaps (pre-1.0)
3534

3635
- **OTLP**: HTTP/protobuf receivers for `/v1/logs` and `/v1/traces` are implemented in `mara-adapter-otlp`; optional gRPC (`:4317` style) logs+traces is available when `grpc_listen` is set. OTLP **HTTP exporters** in sinks are implemented; advanced exporter features remain incremental.

CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ cargo test --workspace
1212
bash scripts/captured/verify_open_verification.sh
1313
```
1414

15+
For the **full** checklist (format, clippy, schema gate, optional Hugo build), see [`INSTALL.md`](INSTALL.md).
16+
1517
The Rust toolchain is pinned in `rust-toolchain.toml`. `rustup` will install it automatically.
1618

1719
## Workflow

INSTALL.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Installing and verifying Mara
2+
3+
This document is the **canonical checklist** for anyone building from `main` (or any release tag). It mirrors what CI runs so you can reproduce a green build locally.
4+
5+
## Prerequisites
6+
7+
| Tool | Notes |
8+
|------|--------|
9+
| **Rust** | Use [rustup](https://rustup.rs/). The repo pins a toolchain in [`rust-toolchain.toml`](rust-toolchain.toml); `rustup` installs it automatically. |
10+
| **Python 3** | For schema completeness and open-verification scripts (stdlib only). |
11+
| **Hugo** (optional) | [Hugo Extended](https://gohugo.io/installation/)**0.120** to build the marketing site under [`website/`](website/README.md). |
12+
13+
## Install from source
14+
15+
```bash
16+
git clone https://github.com/ArdurAI/mara.git
17+
cd mara
18+
cargo build --release -p mara-cli
19+
```
20+
21+
The `mara` binary is at `target/release/mara`. Add it to your `PATH`, or run via `cargo run --release --bin mara -- …`.
22+
23+
### Example configuration
24+
25+
Copy [`examples/mara.toml`](examples/mara.toml) to `mara.toml`, adjust listen addresses and paths, then:
26+
27+
```bash
28+
./target/release/mara validate --config mara.toml
29+
./target/release/mara run --config mara.toml
30+
```
31+
32+
## Verification (same gates as CI)
33+
34+
Run from the repository root, in order:
35+
36+
```bash
37+
# 1. Formatting
38+
cargo fmt --all --check
39+
40+
# 2. Linter (warnings denied)
41+
cargo clippy --workspace --all-targets -- -D warnings
42+
43+
# 3. Unit + integration tests
44+
cargo test --workspace
45+
46+
# 4. Schema completeness gate (fixture fill-rates)
47+
python3 scripts/benchmarks/schema_completeness_gate.py
48+
49+
# 5. Open verification bundles (pinned SHA256)
50+
bash scripts/captured/verify_open_verification.sh
51+
```
52+
53+
**Expected:** every command exits with status **0**. The schema script prints a table (≥85% fill on required fields for qualifying runtimes). The verification script confirms `docs/captured/open-verification/SHASUMS256`.
54+
55+
### Optional: Hugo site
56+
57+
```bash
58+
cd website
59+
hugo --gc --minify
60+
```
61+
62+
Output is `website/public/`. For local preview: `hugo server -D`.
63+
64+
### Optional: Ollama smoke (needs Ollama)
65+
66+
Short cloud smoke (see script header for environment variables):
67+
68+
```bash
69+
bash scripts/realworld/ollama_cloud_smoke.sh
70+
```
71+
72+
## Where results are recorded
73+
74+
| Artifact | Purpose |
75+
|----------|---------|
76+
| `cargo test` | Rust test output in your terminal; CI logs on GitHub Actions. |
77+
| [`docs/captured/open-verification/`](docs/captured/open-verification/README.md) | Redacted JSONL + manifest for reproducible checks. |
78+
| [`.github/workflows/ci.yml`](.github/workflows/ci.yml) | Automated runs on pushes and PRs. |
79+
80+
## Contributing
81+
82+
After the steps above pass, follow [CONTRIBUTING.md](CONTRIBUTING.md) (DCO sign-off, focused PRs).

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Think Fluent Bit for AI workloads: a small, fast, edge-deployable binary that co
66

77
## Status
88

9-
Pre-1.0. Active development on the v1 milestone plan ([MOS plan](plans/mara_mos_plan_d0da16c1.plan.md)).
9+
Pre-1.0. **`main` is expected to stay green** with the checks in [INSTALL.md](INSTALL.md) (format, clippy, tests, schema gate, open-verification SHA256). Feature work may land on `dev` first; releases and default clone experience track **`main`**. Roadmap detail: [MOS plan](plans/mara_mos_plan_d0da16c1.plan.md).
1010

1111
## What Mara captures
1212

@@ -18,7 +18,7 @@ Tier C (analytics REST best-effort): **Augment Code**.
1818

1919
Proxy tier (HTTP request/response capture for runtimes without native telemetry): **Ollama** (local LLM runtime).
2020

21-
**MVP target (in active development on `cursor/mara-mvp` branch):** Claude Code (Tier A) and Ollama (Proxy) end-to-end. The other five runtimes are scaffolded and activate in MVP+1. See [the MVP plan](plans/08-mvp/01-scope-and-decision-criteria.md).
21+
**First-class paths on `main` today:** OTLP HTTP/protobuf (+ optional gRPC when configured), LLM HTTP proxy in front of Ollama/OpenAI-compatible servers, JSONL tail, file/stdout sinks, policy chain (redact, privacy, sample, deny), self-metrics (`/metrics`, `/healthz`, `/readyz`). Tier B/C adapters (hooks HTTP ingest, analytics polling) are configurable from TOML; see [docs/compat-matrix.md](docs/compat-matrix.md) and [the MVP plan](plans/08-mvp/01-scope-and-decision-criteria.md) for depth per runtime.
2222

2323
See the [compatibility matrix specification](plans/05-evaluation/02-compatibility-matrix-spec.md) for details.
2424

@@ -80,6 +80,7 @@ OpenTelemetry Protocol (gRPC + HTTP), Grafana Loki, Splunk HEC, Elasticsearch /
8080
│ └── 07-quickstarts/ # per-runtime onboarding
8181
├── docs/ # engineering reference (ADRs, runbooks)
8282
├── website/ # Hugo static site (project homepage)
83+
├── INSTALL.md # install + verification checklist for main
8384
└── .github/ # CI and governance config
8485
```
8586

@@ -93,13 +94,16 @@ cd website && hugo server -D
9394

9495
See [`website/README.md`](website/README.md) for theme notes, production build, and CI. Set `baseURL` in `website/hugo.toml` before deploying.
9596

96-
## Build
97+
## Install and verify
98+
99+
See **[INSTALL.md](INSTALL.md)** for a full install-from-source walkthrough and the exact command list used to validate `main` (including schema completeness and open-verification bundles).
100+
101+
Quick check:
97102

98103
```bash
99-
cargo check --workspace
100-
cargo test --workspace
101-
cargo clippy --workspace --all-targets -- -D warnings
102104
cargo fmt --all --check
105+
cargo clippy --workspace --all-targets -- -D warnings
106+
cargo test --workspace
103107
```
104108

105109
The Rust toolchain is pinned via `rust-toolchain.toml`. `rustup` installs the right version on first use.
@@ -117,7 +121,7 @@ cargo run --bin mara -- --help
117121
cargo run --bin mara -- version
118122
```
119123

120-
In M0 the CLI is a scaffolded skeleton; real behaviors arrive in M2+ per the [phased milestones](plans/04-implementation/07-phased-milestones.md).
124+
The CLI implements **`mara run`**, **`mara validate`**, **`mara version`**, and **`mara setup`** (presets); behavior is driven by `mara.toml`. See [phased milestones](plans/04-implementation/07-phased-milestones.md) for history and upcoming work.
121125

122126
## Contributing
123127

crates/mara-adapter-analytics/src/lib.rs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use mara_core::error::{Error, Result};
1515
use mara_core::health::Health;
1616
use mara_core::traits::{Adapter, EventSender};
1717
use mara_schema::Event;
18-
use reqwest::header::{ETAG, IF_MODIFIED_SINCE, IF_NONE_MATCH, LAST_MODIFIED};
1918
use reqwest::Url;
19+
use reqwest::header::{ETAG, IF_MODIFIED_SINCE, IF_NONE_MATCH, LAST_MODIFIED};
2020
use tokio::fs;
2121
use tokio::sync::Notify;
2222
use tokio::time::sleep;
@@ -38,7 +38,12 @@ pub struct AnalyticsHttpAdapterConfig {
3838
impl AnalyticsHttpAdapterConfig {
3939
/// Construct from parsed URL and poll settings.
4040
#[must_use]
41-
pub fn new(name: impl Into<String>, url: Url, poll_interval_secs: u64, checkpoint_path: PathBuf) -> Self {
41+
pub fn new(
42+
name: impl Into<String>,
43+
url: Url,
44+
poll_interval_secs: u64,
45+
checkpoint_path: PathBuf,
46+
) -> Self {
4247
Self { name: name.into(), url, poll_interval_secs, checkpoint_path }
4348
}
4449
}
@@ -64,12 +69,9 @@ impl Adapter for AnalyticsHttpAdapter {
6469
}
6570

6671
async fn start(&self, out: EventSender) -> Result<()> {
67-
let client = reqwest::Client::builder()
68-
.timeout(Duration::from_secs(120))
69-
.build()
70-
.map_err(|e| Error::Config {
71-
message: format!("analytics http client: {e}"),
72-
path: None,
72+
let client =
73+
reqwest::Client::builder().timeout(Duration::from_secs(120)).build().map_err(|e| {
74+
Error::Config { message: format!("analytics http client: {e}"), path: None }
7375
})?;
7476
info!(adapter = %self.cfg.name, url = %self.cfg.url, "analytics poller starting");
7577
let stop = self.stop.clone();
@@ -108,9 +110,13 @@ impl Adapter for AnalyticsHttpAdapter {
108110
backoff = (backoff * 2).min(Duration::from_secs(300));
109111
continue;
110112
}
111-
let etag = resp.headers().get(ETAG).and_then(|v| v.to_str().ok()).map(str::to_owned);
112-
let last_modified =
113-
resp.headers().get(LAST_MODIFIED).and_then(|v| v.to_str().ok()).map(str::to_owned);
113+
let etag =
114+
resp.headers().get(ETAG).and_then(|v| v.to_str().ok()).map(str::to_owned);
115+
let last_modified = resp
116+
.headers()
117+
.get(LAST_MODIFIED)
118+
.and_then(|v| v.to_str().ok())
119+
.map(str::to_owned);
114120
let body = match resp.bytes().await {
115121
Ok(b) => b,
116122
Err(e) => {
@@ -131,7 +137,8 @@ impl Adapter for AnalyticsHttpAdapter {
131137
}
132138
}
133139
if let Err(e) =
134-
write_checkpoint(&self.cfg.checkpoint_path, etag, last_modified).await
140+
write_checkpoint(&self.cfg.checkpoint_path, etag, last_modified)
141+
.await
135142
{
136143
warn!(adapter = %self.cfg.name, "checkpoint write: {e}");
137144
}
@@ -193,10 +200,9 @@ async fn write_checkpoint(
193200
last_modified: Option<String>,
194201
) -> Result<()> {
195202
if let Some(parent) = path.parent() {
196-
fs::create_dir_all(parent).await.map_err(|e| Error::Io {
197-
path: Some(parent.display().to_string()),
198-
source: e,
199-
})?;
203+
fs::create_dir_all(parent)
204+
.await
205+
.map_err(|e| Error::Io { path: Some(parent.display().to_string()), source: e })?;
200206
}
201207
let mut s = String::new();
202208
if let Some(e) = etag {
@@ -209,10 +215,9 @@ async fn write_checkpoint(
209215
s.push_str(&l);
210216
s.push('\n');
211217
}
212-
fs::write(path, s).await.map_err(|e| Error::Io {
213-
path: Some(path.display().to_string()),
214-
source: e,
215-
})
218+
fs::write(path, s)
219+
.await
220+
.map_err(|e| Error::Io { path: Some(path.display().to_string()), source: e })
216221
}
217222

218223
fn parse_events_body(body: &[u8]) -> std::result::Result<Vec<Event>, String> {

crates/mara-adapter-hooks/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ impl Adapter for HooksHttpAdapter {
6767
}
6868

6969
async fn start(&self, out: EventSender) -> Result<()> {
70-
let listener = TcpListener::bind(self.cfg.http_listen).await.map_err(|e| {
71-
Error::Io { path: Some(self.cfg.http_listen.to_string()), source: e }
72-
})?;
70+
let listener = TcpListener::bind(self.cfg.http_listen)
71+
.await
72+
.map_err(|e| Error::Io { path: Some(self.cfg.http_listen.to_string()), source: e })?;
7373
info!(adapter = %self.cfg.name, addr = %self.cfg.http_listen, "hooks http listening");
7474
let stop = self.stop.clone();
7575
let max = self.cfg.max_body_bytes;
@@ -173,7 +173,8 @@ fn parse_events(bytes: &[u8]) -> std::result::Result<Vec<Event>, &'static str> {
173173
if let Some(arr) = v.get("events").and_then(Value::as_array) {
174174
let mut out = Vec::with_capacity(arr.len());
175175
for item in arr {
176-
let ev: Event = serde_json::from_value(item.clone()).map_err(|_| "invalid event in events[]")?;
176+
let ev: Event =
177+
serde_json::from_value(item.clone()).map_err(|_| "invalid event in events[]")?;
177178
out.push(ev);
178179
}
179180
if out.is_empty() {

crates/mara-adapter-jsonl/src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,8 @@ async fn tail_one(
152152

153153
#[cfg(all(feature = "notify", unix))]
154154
let fs_wake: Option<std::sync::Arc<Notify>> = if notify_hot_tail {
155-
let parent = path
156-
.parent()
157-
.map(std::path::Path::to_path_buf)
158-
.unwrap_or_else(|| PathBuf::from("."));
155+
let parent =
156+
path.parent().map(std::path::Path::to_path_buf).unwrap_or_else(|| PathBuf::from("."));
159157
let n = std::sync::Arc::new(Notify::new());
160158
spawn_fs_wake_thread(parent, n.clone());
161159
Some(n)

0 commit comments

Comments
 (0)