Esqueleto inicial: sabia-core + sabia-cli + UI local, OpenWolf

- sabia-core: descoberta de interfaces, controle de modo monitor/canal
  via iw (ponte até ter nl80211 nativo), captura crua 802.11 via
  AF_PACKET (sem libpcap), parsing de radiotap e quadros de
  gerenciamento (beacon/probe/EAPOL), agregação em tabela de APs/
  clientes, escrita de .pcap, trilha de auditoria encadeada por hash,
  auto-atualização via GitHub releases (curl, sem dependências de
  rede extras)
- sabia-cli: `sabia iface`, `sabia scan`, `sabia update`,
  `sabia audit-verify`, `sabia ui` (servidor local + navegador,
  protegido por token, mesma filosofia do Guará)
- OpenWolf inicializado para memória de projeto entre agentes
This commit is contained in:
Lucas committed 2026-10-23 08:22:04 -03:00
commit e989413018
76 files changed
+8386

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
# OpenWolf: machine-local state (committed state: cerebrum.md, STATUS.md,
# memory.md, buglog.json, anatomy.md, anatomy-index.json, config.json, OPENWOLF.md)
hooks/
backups/
cache/
daemon.log
daemon.pid
dashboard-token
token-ledger.json
usage-report.json
updates/
handoff/
activity/
usage/
archive/
session-memory/
ledger-pending/
ledger-sessions/
bug-pending/
*.pending/
suggestions.json
cron-state.json
_scan-state.json
_*.json
*.lock
*.tmp
+44
View File
@@ -0,0 +1,44 @@
# OpenWolf Operating Protocol
You are working in an OpenWolf-managed project. These rules apply every turn.
OpenWolf's hooks handle the bookkeeping: they maintain `.wolf/anatomy.md` and `.wolf/memory.md` after writes, track reads, and surface anatomy hints when you read files. Do not update those two files manually unless your agent has no OpenWolf hooks installed (Gemini CLI, Cursor).
## STATUS.md: read first, keep fresh
`.wolf/STATUS.md` is the handoff document. Read it FIRST when resuming a session; it replaces re-reading memory, plans, and code to reconstruct context.
Keep it fresh: when the user signals a quest is done ("done", "ship it", "next phase", "/clear", "wrap up"), move finished items to the done section, write the next quest (objective, files, decisions), and bump the date. Do this before responding "done" on any multi-file task and before suggesting `/clear`. A stale STATUS.md wastes the next session.
## File navigation
1. Before reading an unfamiliar file, grep `.wolf/anatomy.md` for its path to get a one-line description and token estimate. Do NOT read anatomy.md whole; it is an index, not a document.
2. If the description answers your question, skip the full read. For large files, prefer Read with offset/limit over whole-file reads.
3. If a file is not in anatomy.md, search with Grep/Glob. Regenerate the index with `openwolf scan`.
## Code generation
1. Before generating code, check `.wolf/cerebrum.md`: respect `## Do-Not-Repeat` (past mistakes), `## Key Learnings`, and `## User Preferences`.
2. Update cerebrum.md whenever you learn something: a user correction or preference, a project convention not obvious from code, an API surprise, a gotcha that would trip a fresh session, a significant decision and its why. The bar is LOW; a redundant entry costs nothing, a missing one repeats the discovery next session.
## Bug logging
Before fixing any bug: grep `.wolf/buglog.json` for the error message or filename; the fix may already be known.
After fixing any bug, failed test, failed build, or user-reported problem: append an entry with `id`, `timestamp`, `error_message`, `file`, `root_cause`, `fix`, `tags`, `occurrences`, `last_seen`. Also log when you edit a file more than twice to get it right. The threshold is LOW.
## Token discipline
- Never re-read a file already read this session unless it changed since.
- Prefer anatomy descriptions and targeted Grep over full file reads.
- If appending to a file, do not read the entire file first.
## Session end
Before wrapping up: update `.wolf/STATUS.md`, write a one-line session summary to `.wolf/memory.md` (`| HH:MM | description | file(s) | outcome | ~tokens |`), and record any learnings or bugs from the session in cerebrum.md / buglog.json.
## On-demand skills
- `/designqc`: screenshot-based design review of the running app (uses `openwolf designqc`).
- `/reframe`: UI framework selection, migration, and anti-generic design audits.
- `/security-audit`: security review of the project.
+68
View File
@@ -0,0 +1,68 @@
---
description: session handoff, regenerate with /handoff when a quest finishes
budget_tokens: 1000
---
# STATUS — Sabiá
> Single source of truth for resuming work. Read this FIRST when starting a session.
> Update this file at the end of every work phase so the next `/clear` resumes in 1 read.
> Last updated: 2026-10-23
---
## ✅ Done
<!-- Move items here from "🚀 Next phase" when finished. Group by area. -->
- (nothing yet — fill in as work completes)
---
## 🚀 Next phase
**Goal:** _<what we're building next, in 1 sentence>_
### Acceptance criteria
1. _<concrete user-visible outcome>_
2. _<...>_
### Files to create / edit
| Type | File | Content |
|---|---|---|
| new | `path/to/file.ts` | _what it does_ |
### Closed decisions
- _<choice + reasoning>_
### Open decisions
- _<question to ask the user before coding>_
---
## 📁 Active architecture
- **Stack:** _<frameworks, libraries, runtime>_
- **Key tables / modules:** _<list>_
- **Patterns:** _<conventions enforced project-wide>_
---
## ⚠️ External blockers (don't block coding)
- _<env vars, secrets, external accounts, manual steps>_
---
## 🔧 Useful commands
```bash
# add the most-used commands here so the next session has them ready
```
---
## 📚 References (read IF needed)
- `.wolf/cerebrum.md` — User Preferences + Do-Not-Repeat + Decision Log
- `.wolf/anatomy.md` — token-efficient file index
- `.wolf/buglog.json` — known bugs + fixes
+907
View File
@@ -0,0 +1,907 @@
{
"version": 1,
"meta": {
"lastScanned": "2026-10-23T11:21:49.966Z",
"fileCount": 22,
"hits": 0,
"misses": 0,
"renderedHash": "2030278ebfc7a2591c4824586f15125940d579ecad61b4e8cb5a9a9bf6b3a399",
"storeUpdatedAt": "2026-10-23T11:21:49.967Z",
"rootHash": "77f386ab99dd2782"
},
"files": {
".gitignore": {
"description": "Git ignore rules",
"tokens": 24,
"hash": "465569a17f6c1fcd",
"size": 89,
"mtimeMs": 1792754328319.2644,
"updatedAt": "2026-10-23T11:21:49.944Z",
"source": "scan",
"importance": 0.1527
},
"AGENTS.md": {
"description": "OpenWolf",
"tokens": 75,
"hash": "e401f79554a8d796",
"size": 297,
"mtimeMs": 1792754075050.7603,
"updatedAt": "2026-10-23T11:21:49.944Z",
"source": "scan",
"importance": 0.1527
},
"Cargo.toml": {
"description": "Rust package manifest",
"tokens": 100,
"hash": "c445aa952b469eef",
"size": 351,
"mtimeMs": 1792754084001.563,
"updatedAt": "2026-10-23T11:21:49.945Z",
"source": "scan",
"importance": 0.1527
},
"CLAUDE.md": {
"description": "OpenWolf",
"tokens": 99,
"hash": "074d6b42b583729a",
"size": 395,
"mtimeMs": 1792754068779.6982,
"updatedAt": "2026-10-23T11:21:49.945Z",
"source": "scan",
"importance": 0.1527
},
"crates/sabia-cli/Cargo.toml": {
"description": "Rust package manifest",
"tokens": 125,
"hash": "dc1447c043cb895b",
"size": 436,
"mtimeMs": 1792754292996.8179,
"updatedAt": "2026-10-23T11:21:49.945Z",
"source": "scan",
"importance": 0.1527
},
"crates/sabia-cli/src/main.rs": {
"description": "Lista interfaces de rede e mostra quais são Wi-Fi.",
"tokens": 2193,
"hash": "2f37e8d34c3f1e7d",
"size": 7696,
"mtimeMs": 1792754462287.5278,
"updatedAt": "2026-10-23T11:21:49.945Z",
"source": "scan",
"symbols": [
{
"name": "web",
"kind": "section",
"startLine": 1,
"endLine": 1,
"tokens": 3
},
{
"name": "Cli",
"kind": "class",
"startLine": 12,
"endLine": 15,
"tokens": 16
},
{
"name": "Cmd",
"kind": "class",
"startLine": 18,
"endLine": 49,
"tokens": 285
},
{
"name": "IfaceAction",
"kind": "class",
"startLine": 52,
"endLine": 56,
"tokens": 43
},
{
"name": "OnOff",
"kind": "class",
"startLine": 59,
"endLine": 62,
"tokens": 9
},
{
"name": "audit_path",
"kind": "fn",
"startLine": 64,
"endLine": 66,
"tokens": 20
},
{
"name": "main",
"kind": "fn",
"startLine": 68,
"endLine": 74,
"tokens": 41
},
{
"name": "run",
"kind": "fn",
"startLine": 76,
"endLine": 216,
"tokens": 1643
}
],
"symbolSource": "ts",
"skeleton": "mod web;\nstruct Cli {\nenum Cmd {\nenum IfaceAction {\nenum OnOff {\nfn audit_path() -> PathBuf {\nfn main() {\nfn run(cli: Cli) -> sabia_core::Result<()> {",
"imports": [
"crates/sabia-cli/src/web/mod.rs"
],
"importance": 0.1527
},
"crates/sabia-cli/src/web/index.html": {
"description": "Sabiá",
"tokens": 1684,
"hash": "4344229aaa5e2db1",
"size": 6334,
"mtimeMs": 1792754445269.6348,
"updatedAt": "2026-10-23T11:21:49.946Z",
"source": "scan",
"importance": 0.1527
},
"crates/sabia-cli/src/web/mod.rs": {
"description": "Servidor local da interface: a mesma filosofia do Guará (`guara ui`) —",
"tokens": 2254,
"hash": "a6aa02205c19274e",
"size": 7896,
"mtimeMs": 1792754470284.2668,
"updatedAt": "2026-10-23T11:21:49.946Z",
"source": "scan",
"symbols": [
{
"name": "Session",
"kind": "class",
"startLine": 17,
"endLine": 20,
"tokens": 24
},
{
"name": "AppState",
"kind": "class",
"startLine": 23,
"endLine": 25,
"tokens": 19
},
{
"name": "serve",
"kind": "fn",
"startLine": 27,
"endLine": 47,
"tokens": 190
},
{
"name": "gen_token",
"kind": "fn",
"startLine": 49,
"endLine": 53,
"tokens": 52
},
{
"name": "open_browser",
"kind": "fn",
"startLine": 55,
"endLine": 57,
"tokens": 36
},
{
"name": "Request",
"kind": "class",
"startLine": 59,
"endLine": 64,
"tokens": 34
},
{
"name": "parse_request",
"kind": "fn",
"startLine": 66,
"endLine": 94,
"tokens": 286
},
{
"name": "urldecode",
"kind": "fn",
"startLine": 96,
"endLine": 98,
"tokens": 34
},
{
"name": "handle",
"kind": "fn",
"startLine": 100,
"endLine": 119,
"tokens": 227
},
{
"name": "respond",
"kind": "fn",
"startLine": 121,
"endLine": 131,
"tokens": 119
},
{
"name": "api",
"kind": "fn",
"startLine": 133,
"endLine": 174,
"tokens": 531
},
{
"name": "start_scan",
"kind": "fn",
"startLine": 176,
"endLine": 215,
"tokens": 439
},
{
"name": "stop_scan",
"kind": "fn",
"startLine": 217,
"endLine": 222,
"tokens": 60
}
],
"symbolSource": "ts",
"skeleton": "struct Session {\nstruct AppState {\npub fn serve(port: u16) -> sabia_core::Result<()> {\nfn gen_token() -> String {\nfn open_browser(url: &str) -> std::io::Result<()> {\nstruct Request {\nfn parse_request(stream: &mut TcpStream) -> std::io::Result<Request> {\nfn urldecode(s: &str) -> String {\nfn handle(mut stream: TcpStream, state: &Arc<AppState>, expected_token: &str) -> std::io::Result<()> {\nfn respond(stream: &mut TcpStream, code: u16, ctype: &str, body: &[u8]) -> std::io::Result<()> {\nfn api(state: &Arc<AppState>, req: &Request) -> String {\nfn start_scan(state: &Arc<AppState>, name: String) -> String {\nfn stop_scan(state: &Arc<AppState>, name: &str) {",
"importance": 0.2825
},
"crates/sabia-core/Cargo.toml": {
"description": "Rust package manifest",
"tokens": 190,
"hash": "09752951731f7901",
"size": 670,
"mtimeMs": 1792754101085.2576,
"updatedAt": "2026-10-23T11:21:49.946Z",
"source": "scan",
"importance": 0.1527
},
"crates/sabia-core/src/audit.rs": {
"description": "Trilha de auditoria encadeada por hash de toda ação sensível (ligar",
"tokens": 1151,
"hash": "5b60f2b256cb178b",
"size": 4052,
"mtimeMs": 1792754254667.1384,
"updatedAt": "2026-10-23T11:21:49.946Z",
"source": "scan",
"symbols": [
{
"name": "AuditEntry",
"kind": "class",
"startLine": 20,
"endLine": 27,
"tokens": 50
},
{
"name": "AuditLog",
"kind": "class",
"startLine": 29,
"endLine": 32,
"tokens": 22
},
{
"name": "AuditLog",
"kind": "section",
"startLine": 36,
"endLine": 114,
"tokens": 828
},
{
"name": "AuditLog.open",
"kind": "method",
"startLine": 37,
"endLine": 57,
"tokens": 214
},
{
"name": "AuditLog.record",
"kind": "method",
"startLine": 59,
"endLine": 83,
"tokens": 271
},
{
"name": "AuditLog.verify",
"kind": "method",
"startLine": 87,
"endLine": 113,
"tokens": 305
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/error.rs"
],
"importance": 0.1657
},
"crates/sabia-core/src/capture.rs": {
"description": "Captura crua de quadros 802.11 via `AF_PACKET`, sem depender de libpcap.",
"tokens": 1114,
"hash": "b2f202d231708f43",
"size": 3915,
"mtimeMs": 1792754351620.4128,
"updatedAt": "2026-10-23T11:21:49.946Z",
"source": "scan",
"symbols": [
{
"name": "RawCapture",
"kind": "class",
"startLine": 19,
"endLine": 21,
"tokens": 12
},
{
"name": "RawCapture",
"kind": "section",
"startLine": 23,
"endLine": 94,
"tokens": 726
},
{
"name": "RawCapture.open",
"kind": "method",
"startLine": 26,
"endLine": 58,
"tokens": 310
},
{
"name": "RawCapture.set_read_timeout",
"kind": "method",
"startLine": 62,
"endLine": 80,
"tokens": 184
},
{
"name": "RawCapture.recv",
"kind": "method",
"startLine": 83,
"endLine": 93,
"tokens": 126
},
{
"name": "AsRawFd",
"kind": "section",
"startLine": 96,
"endLine": 100,
"tokens": 26
},
{
"name": "AsRawFd.as_raw_fd",
"kind": "method",
"startLine": 97,
"endLine": 99,
"tokens": 16
},
{
"name": "Drop",
"kind": "section",
"startLine": 102,
"endLine": 106,
"tokens": 29
},
{
"name": "Drop.drop",
"kind": "method",
"startLine": 103,
"endLine": 105,
"tokens": 21
},
{
"name": "if_index",
"kind": "fn",
"startLine": 108,
"endLine": 115,
"tokens": 90
},
{
"name": "check_capabilities",
"kind": "fn",
"startLine": 119,
"endLine": 122,
"tokens": 28
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/error.rs"
],
"importance": 0.1657
},
"crates/sabia-core/src/dot11.rs": {
"description": "Parser mínimo de quadros 802.11 de gerenciamento (beacon, probe",
"tokens": 1655,
"hash": "f6ce71057b70544a",
"size": 5804,
"mtimeMs": 1792754184829.32,
"updatedAt": "2026-10-23T11:21:49.946Z",
"source": "scan",
"symbols": [
{
"name": "FrameKind",
"kind": "class",
"startLine": 5,
"endLine": 14,
"tokens": 41
},
{
"name": "Security",
"kind": "class",
"startLine": 17,
"endLine": 23,
"tokens": 20
},
{
"name": "ManagementInfo",
"kind": "class",
"startLine": 26,
"endLine": 30,
"tokens": 37
},
{
"name": "mac_to_string",
"kind": "fn",
"startLine": 32,
"endLine": 34,
"tokens": 44
},
{
"name": "Frame",
"kind": "class",
"startLine": 37,
"endLine": 46,
"tokens": 96
},
{
"name": "parse",
"kind": "fn",
"startLine": 48,
"endLine": 83,
"tokens": 389
},
{
"name": "bssid_str",
"kind": "method",
"startLine": 86,
"endLine": 88,
"tokens": 29
},
{
"name": "src_str",
"kind": "method",
"startLine": 90,
"endLine": 92,
"tokens": 28
},
{
"name": "management_info",
"kind": "method",
"startLine": 96,
"endLine": 162,
"tokens": 635
},
{
"name": "is_eapol",
"kind": "fn",
"startLine": 167,
"endLine": 183,
"tokens": 160
}
],
"symbolSource": "ts",
"importance": 0.2361
},
"crates/sabia-core/src/error.rs": {
"description": "[derive(Debug, thiserror::Error)]",
"tokens": 225,
"hash": "02139521fcac88db",
"size": 797,
"mtimeMs": 1792754108274.089,
"updatedAt": "2026-10-23T11:21:49.947Z",
"source": "scan",
"importance": 1
},
"crates/sabia-core/src/iface.rs": {
"description": "Descoberta de interfaces de rede e identificação das que são Wi-Fi.",
"tokens": 973,
"hash": "bc45dfdc47a527fc",
"size": 3427,
"mtimeMs": 1792754124447.7615,
"updatedAt": "2026-10-23T11:21:49.947Z",
"source": "scan",
"symbols": [
{
"name": "Interface",
"kind": "class",
"startLine": 11,
"endLine": 18,
"tokens": 59
},
{
"name": "Mode",
"kind": "class",
"startLine": 21,
"endLine": 25,
"tokens": 16
},
{
"name": "net_root",
"kind": "fn",
"startLine": 27,
"endLine": 29,
"tokens": 19
},
{
"name": "list_all",
"kind": "fn",
"startLine": 32,
"endLine": 44,
"tokens": 110
},
{
"name": "list_wireless",
"kind": "fn",
"startLine": 47,
"endLine": 49,
"tokens": 35
},
{
"name": "get",
"kind": "fn",
"startLine": 51,
"endLine": 57,
"tokens": 57
},
{
"name": "read_interface",
"kind": "fn",
"startLine": 59,
"endLine": 98,
"tokens": 372
},
{
"name": "read_wireless_mode",
"kind": "fn",
"startLine": 104,
"endLine": 110,
"tokens": 62
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/error.rs"
],
"importance": 0.2361
},
"crates/sabia-core/src/lib.rs": {
"description": "`sabia-core`: tudo que fala com o rádio Wi-Fi, interpreta quadros 802.11",
"tokens": 140,
"hash": "e65164872526b1e7",
"size": 495,
"mtimeMs": 1792754288188.87,
"updatedAt": "2026-10-23T11:21:49.947Z",
"source": "scan",
"imports": [
"crates/sabia-core/src/audit.rs",
"crates/sabia-core/src/dot11.rs",
"crates/sabia-core/src/error.rs",
"crates/sabia-core/src/iface.rs",
"crates/sabia-core/src/netlink.rs",
"crates/sabia-core/src/pcapwriter.rs",
"crates/sabia-core/src/radiotap.rs",
"crates/sabia-core/src/scan.rs",
"crates/sabia-core/src/update.rs",
"crates/sabia-core/src/capture.rs"
],
"importance": 0.1527
},
"crates/sabia-core/src/netlink.rs": {
"description": "Controle de modo (managed/monitor) e canal via `iw`.",
"tokens": 996,
"hash": "6a27b03cef2c283e",
"size": 3500,
"mtimeMs": 1792754142459.2986,
"updatedAt": "2026-10-23T11:21:49.947Z",
"source": "scan",
"symbols": [
{
"name": "run",
"kind": "fn",
"startLine": 13,
"endLine": 34,
"tokens": 246
},
{
"name": "iw_dev_type",
"kind": "fn",
"startLine": 36,
"endLine": 49,
"tokens": 123
},
{
"name": "supported_channels",
"kind": "fn",
"startLine": 52,
"endLine": 80,
"tokens": 294
},
{
"name": "set_monitor_mode",
"kind": "fn",
"startLine": 83,
"endLine": 89,
"tokens": 84
},
{
"name": "set_channel",
"kind": "fn",
"startLine": 92,
"endLine": 95,
"tokens": 42
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/error.rs",
"crates/sabia-core/src/iface.rs"
],
"importance": 0.1657
},
"crates/sabia-core/src/pcapwriter.rs": {
"description": "Escritor de arquivos `.pcap` (formato clássico, link-type 127 =",
"tokens": 507,
"hash": "2d6921c66f9e7506",
"size": 1781,
"mtimeMs": 1792754240112.29,
"updatedAt": "2026-10-23T11:21:49.947Z",
"source": "scan",
"symbols": [
{
"name": "PcapWriter",
"kind": "class",
"startLine": 13,
"endLine": 15,
"tokens": 15
},
{
"name": "PcapWriter",
"kind": "section",
"startLine": 17,
"endLine": 47,
"tokens": 379
},
{
"name": "PcapWriter.create",
"kind": "method",
"startLine": 18,
"endLine": 30,
"tokens": 186
},
{
"name": "PcapWriter.write_frame",
"kind": "method",
"startLine": 33,
"endLine": 41,
"tokens": 140
},
{
"name": "PcapWriter.flush",
"kind": "method",
"startLine": 43,
"endLine": 46,
"tokens": 26
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/error.rs"
],
"importance": 0.1657
},
"crates/sabia-core/src/radiotap.rs": {
"description": "Parser mínimo de cabeçalho Radiotap — só os campos que usamos",
"tokens": 881,
"hash": "3dc5e23c73e7e66a",
"size": 3104,
"mtimeMs": 1792754360436.5854,
"updatedAt": "2026-10-23T11:21:49.948Z",
"source": "scan",
"symbols": [
{
"name": "RadiotapInfo",
"kind": "class",
"startLine": 6,
"endLine": 10,
"tokens": 34
},
{
"name": "parse",
"kind": "fn",
"startLine": 20,
"endLine": 94,
"tokens": 626
},
{
"name": "freq_to_channel",
"kind": "fn",
"startLine": 96,
"endLine": 103,
"tokens": 73
}
],
"symbolSource": "ts",
"importance": 0.2361
},
"crates/sabia-core/src/scan.rs": {
"description": "Agregação de quadros capturados em uma tabela de APs e clientes vistos,",
"tokens": 1128,
"hash": "bcd7f984398bfdc4",
"size": 3963,
"mtimeMs": 1792754229534.2896,
"updatedAt": "2026-10-23T11:21:49.948Z",
"source": "scan",
"symbols": [
{
"name": "AccessPoint",
"kind": "class",
"startLine": 11,
"endLine": 20,
"tokens": 76
},
{
"name": "ScanTable",
"kind": "class",
"startLine": 23,
"endLine": 25,
"tokens": 18
},
{
"name": "ScanTable",
"kind": "section",
"startLine": 27,
"endLine": 102,
"tokens": 842
},
{
"name": "ScanTable.new",
"kind": "method",
"startLine": 28,
"endLine": 30,
"tokens": 16
},
{
"name": "ScanTable.ingest",
"kind": "method",
"startLine": 36,
"endLine": 95,
"tokens": 696
},
{
"name": "ScanTable.access_points",
"kind": "method",
"startLine": 97,
"endLine": 101,
"tokens": 57
},
{
"name": "security_label",
"kind": "fn",
"startLine": 104,
"endLine": 112,
"tokens": 77
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/dot11.rs",
"crates/sabia-core/src/radiotap.rs"
],
"importance": 0.1657
},
"crates/sabia-core/src/update.rs": {
"description": "Auto-atualização simples: verifica a última release no GitHub, baixa o",
"tokens": 1772,
"hash": "03ad228ca62475e3",
"size": 6236,
"mtimeMs": 1792754282046.0845,
"updatedAt": "2026-10-23T11:21:49.948Z",
"source": "scan",
"symbols": [
{
"name": "Release",
"kind": "class",
"startLine": 18,
"endLine": 21,
"tokens": 19
},
{
"name": "Asset",
"kind": "class",
"startLine": 24,
"endLine": 27,
"tokens": 20
},
{
"name": "UpdateStatus",
"kind": "class",
"startLine": 30,
"endLine": 34,
"tokens": 38
},
{
"name": "curl_text",
"kind": "fn",
"startLine": 36,
"endLine": 48,
"tokens": 152
},
{
"name": "curl_download",
"kind": "fn",
"startLine": 50,
"endLine": 61,
"tokens": 138
},
{
"name": "asset_name_for_platform",
"kind": "fn",
"startLine": 63,
"endLine": 73,
"tokens": 91
},
{
"name": "check",
"kind": "fn",
"startLine": 77,
"endLine": 99,
"tokens": 260
},
{
"name": "apply",
"kind": "fn",
"startLine": 103,
"endLine": 162,
"tokens": 693
},
{
"name": "find_binary",
"kind": "fn",
"startLine": 164,
"endLine": 173,
"tokens": 109
}
],
"symbolSource": "ts",
"imports": [
"crates/sabia-core/src/error.rs"
],
"importance": 0.1657
},
"GEMINI.md": {
"description": "OpenWolf",
"tokens": 75,
"hash": "e401f79554a8d796",
"size": 297,
"mtimeMs": 1792754075057.7603,
"updatedAt": "2026-10-23T11:21:49.948Z",
"source": "scan",
"importance": 0.1527
},
"README.md": {
"description": "Project documentation",
"tokens": 462,
"hash": "04a8387e4a13cf9f",
"size": 1887,
"mtimeMs": 1792754508878.1196,
"updatedAt": "2026-10-23T11:21:49.949Z",
"source": "scan",
"importance": 0.1527
}
},
"preamble": [
"> Project structure index. Auto-maintained by OpenWolf hooks and daemon.",
"> Run `openwolf scan` to generate, or wait for the first Claude Code session.",
"> Status: Pending initial scan"
]
}
+48
View File
@@ -0,0 +1,48 @@
# anatomy.md
> Auto-maintained by OpenWolf. Last scanned: 2026-10-23T11:21:49.966Z
> Files: 22 tracked | Anatomy hits: 0 | Misses: 0
> Project structure index. Auto-maintained by OpenWolf hooks and daemon.
> Run `openwolf scan` to generate, or wait for the first Claude Code session.
> Status: Pending initial scan
## ./
- `.gitignore` — Git ignore rules (~24 tok)
- `AGENTS.md` — OpenWolf (~75 tok)
- `Cargo.toml` — Rust package manifest (~100 tok)
- `CLAUDE.md` — OpenWolf (~99 tok)
- `GEMINI.md` — OpenWolf (~75 tok)
- `README.md` — Project documentation (~462 tok)
## crates/sabia-cli/
- `Cargo.toml` — Rust package manifest (~125 tok)
## crates/sabia-cli/src/
- `main.rs` — Lista interfaces de rede e mostra quais são Wi-Fi. (~2193 tok)
## crates/sabia-cli/src/web/
- `index.html` — Sabiá (~1684 tok)
- `mod.rs` — Servidor local da interface: a mesma filosofia do Guará (`guara ui`) — (~2254 tok)
## crates/sabia-core/
- `Cargo.toml` — Rust package manifest (~190 tok)
## crates/sabia-core/src/
- `audit.rs` — Trilha de auditoria encadeada por hash de toda ação sensível (ligar (~1151 tok)
- `capture.rs` — Captura crua de quadros 802.11 via `AF_PACKET`, sem depender de libpcap. (~1114 tok)
- `dot11.rs` — Parser mínimo de quadros 802.11 de gerenciamento (beacon, probe (~1655 tok)
- `error.rs` — [derive(Debug, thiserror::Error)] (~225 tok)
- `iface.rs` — Descoberta de interfaces de rede e identificação das que são Wi-Fi. (~973 tok)
- `lib.rs` — `sabia-core`: tudo que fala com o rádio Wi-Fi, interpreta quadros 802.11 (~140 tok)
- `netlink.rs` — Controle de modo (managed/monitor) e canal via `iw`. (~996 tok)
- `pcapwriter.rs` — Escritor de arquivos `.pcap` (formato clássico, link-type 127 = (~507 tok)
- `radiotap.rs` — Parser mínimo de cabeçalho Radiotap — só os campos que usamos (~881 tok)
- `scan.rs` — Agregação de quadros capturados em uma tabela de APs e clientes vistos, (~1128 tok)
- `update.rs` — Auto-atualização simples: verifica a última release no GitHub, baixa o (~1772 tok)
+27
View File
@@ -0,0 +1,27 @@
{
"version": 1,
"bugs": [
{
"error_message": "Wrong reference: Read should be Write",
"file": "crates/sabia-cli/src/web/mod.rs",
"root_cause": "Used \"Read\" instead of \"Write\"",
"fix": "Changed Read → Write",
"tags": [
"auto-detected",
"wrong-reference",
"rs"
],
"status": "candidate",
"observed_worktree": "/home/lucas/Documents/Pessoal/dev/Sabiá",
"id": "bug-001",
"timestamp": "2026-10-23T11:21:10.367Z",
"last_seen": "2026-10-23T11:21:10.367Z",
"occurrences": 1,
"related_bugs": []
}
],
"applied_observations": {
"0c11d054-2b71-4e02-a624-0e73a302bc1e": true
},
"next_id": 2
}
+26
View File
@@ -0,0 +1,26 @@
---
description: learned preferences, project conventions, and Do-Not-Repeat rules
budget_tokens: 2000
---
# Cerebrum
> OpenWolf's learning memory. Updated automatically as the AI learns from interactions.
> Do not edit manually unless correcting an error.
> Last updated: 2026-10-23
## User Preferences
<!-- How the user likes things done. Code style, tools, patterns, communication. -->
## Key Learnings
- **Project:** Sabiá
## Do-Not-Repeat
<!-- Mistakes made and corrected. Each entry prevents the same mistake recurring. -->
<!-- Format: [YYYY-MM-DD] Description of what went wrong and what to do instead. -->
## Decision Log
<!-- Significant technical decisions with rationale. Why X was chosen over Y. -->
+126
View File
@@ -0,0 +1,126 @@
{
"version": 1,
"openwolf": {
"enabled": true,
"reads": {
"duplicate_mode": "warn",
"skeleton_hints": true
},
"bash": {
"filter_mode": "suggest",
"governor": {
"mode": "replace",
"threshold_tokens": 2000,
"families": {
"grep_flood": "replace",
"file_print": "replace",
"git_show": "replace",
"test": "suggest",
"build": "suggest",
"unknown": "suggest"
}
}
},
"anatomy": {
"auto_scan_on_init": true,
"rescan_interval_hours": 6,
"max_description_length": 100,
"max_files": 500,
"exclude_patterns": [
"node_modules",
"dist",
"build",
".next",
".nuxt",
".turbo",
".vercel",
".netlify",
".output",
"coverage",
"__pycache__",
".venv",
"venv",
"site-packages",
".pytest_cache",
".mypy_cache",
".ruff_cache",
".tox",
"*.pyc",
".gradle",
"target",
".m2",
".cargo",
".git",
".wolf",
".cache",
".vscode",
".idea",
".DS_Store",
"Thumbs.db",
"*.min.js",
"*.min.css",
"*.map"
],
"respect_gitignore": true
},
"token_audit": {
"enabled": true,
"report_frequency": "weekly",
"waste_threshold_percent": 15,
"chars_per_token_code": 3.5,
"chars_per_token_prose": 4
},
"cron": {
"enabled": true,
"max_retry_attempts": 3,
"dead_letter_enabled": true,
"heartbeat_interval_minutes": 30
},
"memory": {
"consolidation_after_days": 7,
"max_entries_before_consolidation": 200
},
"cerebrum": {
"max_tokens": 2000,
"reflection_frequency": "weekly"
},
"daemon": {
"port": 18830,
"log_level": "info"
},
"dashboard": {
"enabled": true,
"port": 18831,
"host": "127.0.0.1"
},
"context": {
"session_digest_budget_tokens": 1500,
"reinjection_interval": 25,
"state_budgets": {
".wolf/cerebrum.md": 2000,
".wolf/STATUS.md": 1000
},
"budgets": {
"claude": 1500,
"codex": 1200,
"gemini": 1200,
"opencode": 1200,
"cursor": 800
}
},
"visibility": {
"mode": "quiet"
},
"updates": {
"mode": "compatible"
},
"agents": [
"claude",
"codex",
"opencode",
"gemini",
"cursor",
"antigravity"
]
}
}
+66
View File
@@ -0,0 +1,66 @@
{
"version": 1,
"tasks": [
{
"id": "anatomy-rescan",
"name": "Full anatomy rescan",
"schedule": "0 */6 * * *",
"description": "Re-scans project filesystem and reconciles anatomy.md",
"action": {
"type": "scan_project"
},
"retry": {
"max_attempts": 3,
"backoff": "exponential",
"base_delay_seconds": 30
},
"failsafe": {
"on_failure": "log_and_continue",
"alert_after_consecutive_failures": 2,
"dead_letter": true
},
"enabled": true
},
{
"id": "memory-consolidation",
"name": "Consolidate old memory",
"schedule": "0 2 * * *",
"description": "Compress memory.md entries older than 7 days",
"action": {
"type": "consolidate_memory",
"params": {
"older_than_days": 7
}
},
"retry": {
"max_attempts": 2,
"backoff": "exponential",
"base_delay_seconds": 60
},
"failsafe": {
"on_failure": "skip_and_retry_next_cycle",
"dead_letter": false
},
"enabled": true
},
{
"id": "token-audit",
"name": "Token audit report",
"schedule": "0 0 * * 1",
"description": "Weekly waste pattern detection",
"action": {
"type": "generate_token_report"
},
"retry": {
"max_attempts": 2,
"backoff": "linear",
"base_delay_seconds": 60
},
"failsafe": {
"on_failure": "log_and_continue",
"dead_letter": true
},
"enabled": true
}
]
}
+34
View File
@@ -0,0 +1,34 @@
---
description: chronological action log per session, consolidated weekly
---
# Memory
> Chronological action log. Hooks and AI append to this file automatically.
> Old sessions are consolidated by the daemon weekly.
| 08:14 | Created Cargo.toml | — | ~94 |
| 08:15 | Created crates/sabia-core/Cargo.toml | — | ~177 |
| 08:15 | Created crates/sabia-core/src/error.rs | — | ~210 |
| 08:15 | Created crates/sabia-core/src/iface.rs | — | ~908 |
| 08:15 | Created crates/sabia-core/src/netlink.rs | — | ~930 |
| 08:16 | Created crates/sabia-core/src/radiotap.rs | — | ~828 |
| 08:16 | Created crates/sabia-core/src/dot11.rs | — | ~1544 |
| 08:16 | Created crates/sabia-core/src/capture.rs | — | ~1069 |
| 08:16 | Edited crates/sabia-core/src/capture.rs | 3→3 lines | ~17 |
| 08:16 | Edited crates/sabia-core/src/capture.rs | — | ~0 |
| 08:17 | Created crates/sabia-core/src/scan.rs | — | ~1053 |
| 08:17 | Created crates/sabia-core/src/pcapwriter.rs | — | ~474 |
| 08:17 | Created crates/sabia-core/src/audit.rs | — | ~1074 |
| 08:18 | Created crates/sabia-core/src/update.rs | — | ~1654 |
| 08:18 | Created crates/sabia-core/src/lib.rs | — | ~131 |
| 08:18 | Created crates/sabia-cli/Cargo.toml | — | ~117 |
| 08:18 | Created crates/sabia-cli/src/main.rs | — | ~1987 |
| 08:18 | Created .gitignore | — | ~24 |
| 08:19 | Edited crates/sabia-core/src/capture.rs | inline fix | ~18 |
| 08:19 | Edited crates/sabia-core/src/radiotap.rs | modified len() | ~47 |
| 08:20 | Created crates/sabia-cli/src/web/mod.rs | — | ~2105 |
| 08:20 | Created crates/sabia-cli/src/web/index.html | — | ~1684 |
| 08:20 | Edited crates/sabia-cli/src/main.rs | 6→8 lines | ~72 |
| 08:20 | Edited crates/sabia-cli/src/main.rs | 3→8 lines | ~63 |
| 08:21 | Edited crates/sabia-cli/src/main.rs | 5→9 lines | ~83 |
| 08:21 | Edited crates/sabia-cli/src/web/mod.rs | inline fix | ~11 |
| 08:21 | Created README.md | — | ~493 |