NagyZoltanPeter 42e0aa43d1
feat: persistency (#3880)
* persistency: per-job SQLite-backed storage layer (singleton, brokered)

Adds a backend-neutral CRUD library at waku/persistency/, plus the
nim-brokers dependency swap that enables it.

Architecture (ports-and-adapters):
  * Persistency: process-wide singleton, one root directory.
  * Job: one tenant, one DB file, one worker thread, one BrokerContext.
  * Backend: SQLite via waku/common/databases/db_sqlite. Uniform schema
    kv(category BLOB, key BLOB, payload BLOB) PRIMARY KEY (category, key)
    WITHOUT ROWID, WAL mode.
  * Writes are fire-and-forget via EventBroker(mt) PersistEvent.
  * Reads are async via five RequestBroker(mt) shapes (KvGet, KvExists,
    KvScan, KvCount, KvDelete). Reads return Result[T, PersistencyError].
  * One storage thread per job; tenants isolated by BrokerContext.

Public surface (waku/persistency/persistency.nim):
  Persistency.instance(rootDir) / Persistency.instance() / Persistency.reset()
  p.openJob(id) / p.closeJob(id) / p.dropJob(id) / p.close()
  p.job(id) / p[id] / p.hasJob(id)
  Writes (Job form & string-id form, fire-and-forget):
    persist / persistPut / persistDelete / persistEncoded
  Reads (Job form & string-id form, async Result):
    get / exists / scan / scanPrefix / count / deleteAcked

Key & payload encoding (keys.nim, payload.nim):
  * encodePart family + variadic key(...) / payload(...) macros +
    single-value toKey / toPayload.
  * Primitives: string and openArray[byte] are 2-byte BE length + bytes;
    int{8..64} are sign-flipped 8-byte BE; uint{16..64} are 8-byte BE;
    bool/byte/char are 1 byte; enums are int64(ord(v)).
  * Generic encodePart[T: tuple | object] recurses through fields() so
    any composite Nim type is encodable without ceremony.
  * Stable across Nim/C compiler upgrades: no sizeof, no memcpy, no
    cast on pointers, no host-endianness dependency.
  * `rawKey(bytes)` + `persistPut(..., openArray[byte])` let callers
    bypass the built-in encoder with their own format (CBOR, protobuf...).

Lifecycle:
  * Persistency.new is private; Persistency.instance is the only public
    constructor. Same rootDir is idempotent; conflicting rootDir is
    peInvalidArgument. Persistency.reset for test/restart paths.
  * openJob opens-or-creates the per-job SQLite file; an existing file
    is reused with its data preserved.
  * Teardown integration: Persistency.instance registers a Teardown
    MultiRequestBroker provider that closes all jobs and clears the
    singleton slot when Waku.stop() issues Teardown.request.

Internal layering:
  types.nim          pure value types (Key, KeyRange, KvRow, TxOp,
                     PersistencyError)
  keys.nim           encodePart primitives + key(...) macro
  payload.nim        toPayload + payload(...) macro
  schema.nim         CREATE TABLE + connection pragmas + user_version
  backend_sqlite.nim KvBackend, applyOps (single source of write SQL),
                     getOne/existsOne/deleteOne, scanRange (asc/desc,
                     half-open ranges, open-ended stop), countRange
  backend_comm.nim   EventBroker(mt) PersistEvent + 5 RequestBroker(mt)
                     declarations; encodeErr/decodeErr boundary helpers
  backend_thread.nim startStorageThread / stopStorageThread (shared
                     allocShared0 arg, cstring dbPath, atomic
                     ready/shutdown flags); per-thread provider
                     registration
  persistency.nim    Persistency + Job types, singleton state, public
                     facade
  ../requests/lifecycle_requests.nim
                     Teardown MultiRequestBroker

Tests (69 cases, all passing):
  test_keys.nim          sort-order invariants (length-prefix strings,
                         sign-flipped ints, composite tuples, prefix
                         range)
  test_backend.nim       round-trip / replace / delete-return-value /
                         batched atomicity / asc-desc-half-open-open-
                         ended scans / category isolation / batch
                         txDelete
  test_lifecycle.nim     open-or-create rootDir / non-dir collision /
                         reopen across sessions / idempotent openJob /
                         two-tenant parallel isolation / closeJob joins
                         worker / dropJob removes file / acked delete
  test_facade.nim        put-then-get / atomic batch / scanPrefix
                         asc/desc / deleteAcked hit-miss /
                         fire-and-forget delete / two-tenant facade
                         isolation
  test_encoding.nim      tuple/named-tuple/object keys, embedded Key,
                         enum encoding, field-major composite sort,
                         payload struct encoding, end-to-end struct
                         round-trip through SQLite
  test_string_lookup.nim peJobNotFound semantics / hasJob / subscript /
                         persistPut+get via id / reads short-circuit /
                         writes drop+warn / persistEncoded via id /
                         scan parity Job-ref vs id
  test_singleton.nim     idempotent same-rootDir / different-rootDir
                         rejection / no-arg instance lifecycle / reset
                         retargets / reset idempotence / Teardown.request
                         end-to-end

Prerequisite delivered in the same series: replace the in-tree broker
implementation with the external nim-brokers package; update all
broker call-sites (waku_filter_v2, waku_relay, waku_rln_relay,
delivery_service, peer_manager, requests/*, factory/*, api tests, etc.)
to the new package API; chat2 made to compile again.

Note: SDS adapter (Phase 5 of the design) is deferred -- nim-sds is
still developed side-by-side and the persistency layer is intentionally
SDS-agnostic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* persistency: pin nim-brokers by URL+commit (workaround for stale registry)

The bare `brokers >= 2.0.1` form cannot resolve on machines where the
local nimble SAT solver enumerates only the registry-recorded 0.1.0 for
brokers. The nim-lang/packages entry for `brokers` carries no per-tag
metadata (only the URL), so until that registry entry is refreshed the
SAT solver clamps the available-versions list to 0.1.0 and rejects the
>= 2.0.1 constraint -- even though pkgs2 and pkgcache both have v2.0.1
cloned locally.

Pinning by URL+commit bypasses the registry path entirely. Inline
comment in waku.nimble documents the situation and the path back to
the bare form once nim-lang/packages is updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* persistency: nph format pass

Run `nph` on all 57 Nim files touched by this PR. Pure formatting:
17 files re-styled, no semantic change. Suite still 69/69.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Fix build, add local-storage-path config, lazy init of Persistency from Waku start

* fix: fix nix deps

* fixes for nix build, regenerate deps

* reverting accidental dependency changes

* Fixing deps

* Apply suggestions from code review

Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>

* persistency tests: migrate to suite / asyncTest / await

Match the in-tree test convention (procSuite -> suite, sync test +
waitFor -> asyncTest + await):

- procSuite "X": -> suite "X":
- For tests doing async work: test -> asyncTest, waitFor -> await.
- Poll helpers (proc waitFor(t: Job, ...) in test_lifecycle.nim,
  proc waitUntilExists(...) in test_facade.nim and
  test_string_lookup.nim) -> Future[bool] {.async.}, internal
  `waitFor X` -> `await X`, internal `sleep(N)` ->
  `await sleepAsync(chronos.milliseconds(N))`.
- Renamed test_lifecycle.nim's helper proc from `waitFor(t: Job, ...)`
  -> `pollExists(t: Job, ...)`; the previous name shadowed
  chronos.waitFor in the chronos macro expansion.
- `chronos.milliseconds(N)` explicitly qualified because `std/times`
  also exports `milliseconds` (returning TimeInterval, not Duration).
- `check await x` -> `let okN = await x; check okN` to dodge chronos's
  "yield in expr not lowered" with await-as-macro-argument.
- `(await x).foo()` -> `let awN = await x; ... awN.foo() ...` for the
  same reason.

waku/persistency/persistency.nim: nph also pulled the proc signatures
across multiple lines; restored explicit `Future[void] {.async.}`
return types after the colon (an intermediate nph pass had elided them).

Suite: 71 / 71 OK against the new async write surface.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* use idiomatic valueOr instead of ifs

* Reworked persistency shutdown, remove not necessary teardown mechanism

* Use const for DefaultStoragePath

* format to follow coding guidelines - no use of result and explicit returns - no functional change

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
2026-05-16 00:09:07 +02:00

19 KiB

AGENTS.md - AI Coding Context

This file provides essential context for LLMs assisting with Logos Messaging development.

Project Identity

Logos Messaging is designed as a shared public network for generalized messaging, not application-specific infrastructure.

This project is a Nim implementation of a libp2p protocol suite for private, censorship-resistant P2P messaging. It targets resource-restricted devices and privacy-preserving communication.

Logos Messaging was formerly known as Waku. Waku-related terminology remains within the codebase for historical reasons.

Design Philosophy

Key architectural decisions:

Resource-restricted first: Protocols differentiate between full nodes (relay) and light clients (filter, lightpush, store). Light clients can participate without maintaining full message history or relay capabilities. This explains the client/server split in protocol implementations.

Privacy through unlinkability: RLN (Rate Limiting Nullifier) provides DoS protection while preserving sender anonymity. Messages are routed through pubsub topics with automatic sharding across 8 shards. Code prioritizes metadata privacy alongside content encryption.

Scalability via sharding: The network uses automatic content-topic-based sharding to distribute traffic. This is why you'll see sharding logic throughout the codebase and why pubsub topic selection is protocol-level, not application-level.

See documentation for architectural details.

Core Protocols

  • Relay: Pub/sub message routing using GossipSub
  • Store: Historical message retrieval and persistence
  • Filter: Lightweight message filtering for resource-restricted clients
  • Lightpush: Lightweight message publishing for clients
  • Peer Exchange: Peer discovery mechanism
  • RLN Relay: Rate limiting nullifier for spam protection
  • Metadata: Cluster and shard metadata exchange between peers
  • Mix: Mixnet protocol for enhanced privacy through onion routing
  • Rendezvous: Alternative peer discovery mechanism

Key Terminology

  • ENR (Ethereum Node Record): Node identity and capability advertisement
  • Multiaddr: libp2p addressing format (e.g., /ip4/127.0.0.1/tcp/60000/p2p/16Uiu2...)
  • PubsubTopic: Gossipsub topic for message routing (e.g., /waku/2/default-waku/proto)
  • ContentTopic: Application-level message categorization (e.g., /my-app/1/chat/proto)
  • Sharding: Partitioning network traffic across topics (static or auto-sharding)
  • RLN (Rate Limiting Nullifier): Zero-knowledge proof system for spam prevention

Specifications

All specs are at rfc.vac.dev/waku. RFCs use WAKU2-XXX format (not legacy WAKU-XXX).

Architecture

Protocol Module Pattern

Each protocol typically follows this structure:

waku_<protocol>/
├── protocol.nim       # Main protocol type and handler logic
├── client.nim         # Client-side API
├── rpc.nim           # RPC message types
├── rpc_codec.nim     # Protobuf encoding/decoding
├── common.nim        # Shared types and constants
└── protocol_metrics.nim  # Prometheus metrics

WakuNode Architecture

  • WakuNode (waku/node/waku_node.nim) is the central orchestrator
  • Protocols are "mounted" onto the node's switch (libp2p component)
  • PeerManager handles peer selection and connection management
  • Switch provides libp2p transport, security, and multiplexing

Example protocol type definition:

type WakuFilter* = ref object of LPProtocol
  subscriptions*: FilterSubscriptions
  peerManager: PeerManager
  messageCache: TimedCache[string]

Development Essentials

Build Requirements

  • Nim 2.x (check waku.nimble for minimum version)
  • Rust toolchain (required for RLN dependencies)
  • Build system: Make with nimbus-build-system

Build System

The project uses Makefile with nimbus-build-system (Status's Nim build framework):

# Initial build (updates submodules)
make wakunode2

# After git pull, update submodules
make update

# Build with custom flags
make wakunode2 NIMFLAGS="-d:chronicles_log_level=DEBUG"

Note: The build system uses --mm:refc memory management (automatically enforced). Only relevant if compiling outside the standard build system.

Common Make Targets

make wakunode2          # Build main node binary
make test               # Run all tests
make testcommon         # Run common tests only
make libwakuStatic      # Build static C library
make chat2              # Build chat example
make install-nph        # Install git hook for auto-formatting

Testing

# Run all tests
make test

# Run specific test file
make test tests/test_waku_enr.nim

# Run specific test case from file
make test tests/test_waku_enr.nim "check capabilities support"

# Build and run test separately (for development iteration)
make test tests/test_waku_enr.nim

Test structure uses testutils/unittests:

import testutils/unittests

suite "Waku ENR - Capabilities":
  test "check capabilities support":
    ## Given
    let bitfield: CapabilitiesBitfield = 0b0000_1101u8
    
    ## Then
    check:
      bitfield.supportsCapability(Capabilities.Relay)
      not bitfield.supportsCapability(Capabilities.Store)

Code Formatting

Mandatory: All code must be formatted with nph (vendored in vendor/nph)

# Format specific file
make nph/waku/waku_core.nim

# Install git pre-commit hook (auto-formats on commit)
make install-nph

The nph formatter handles all formatting details automatically, especially with the pre-commit hook installed. Focus on semantic correctness.

Logging

Uses chronicles library with compile-time configuration:

import chronicles

logScope:
  topics = "waku lightpush"

info "handling request", peerId = peerId, topic = pubsubTopic
error "request failed", error = msg

Compile with log level:

nim c -d:chronicles_log_level=TRACE myfile.nim

Code Conventions

Common pitfalls:

  • Always handle Result types explicitly
  • Avoid global mutable state: Pass state through parameters
  • Keep functions focused: Under 50 lines when possible
  • Prefer compile-time checks (static assert) over runtime checks

Naming

  • Files/Directories: snake_case (e.g., waku_lightpush, peer_manager)
  • Procedures: camelCase (e.g., handleRequest, pushMessage)
  • Types: PascalCase (e.g., WakuFilter, PubsubTopic)
  • Constants: PascalCase (e.g., MaxContentTopicsPerRequest)
  • Constructors: func init(T: type Xxx, params): T
  • For ref types: func new(T: type Xxx, params): ref T
  • Exceptions: XxxError for CatchableError, XxxDefect for Defect
  • ref object types: XxxRef suffix

Imports Organization

Group imports: stdlib, external libs, internal modules:

import
  std/[options, sequtils],      # stdlib
  results, chronicles, chronos,  # external
  libp2p/peerid
import
  ../node/peer_manager,          # internal (separate import block)
  ../waku_core,
  ./common

Async Programming

Uses chronos, not stdlib asyncdispatch:

proc handleRequest(
    wl: WakuLightPush, peerId: PeerId
): Future[WakuLightPushResult] {.async.} =
  let res = await wl.pushHandler(peerId, pubsubTopic, message)
  return res

Error Handling

The project uses both Result types and exceptions:

Result types from nim-results are used for protocol and API-level errors:

proc subscribe(
    wf: WakuFilter, peerId: PeerID
): Future[FilterSubscribeResult] {.async.} =
  if contentTopics.len > MaxContentTopicsPerRequest:
    return err(FilterSubscribeError.badRequest("exceeds maximum"))
  
  # Handle Result with isOkOr
  (await wf.subscriptions.addSubscription(peerId, criteria)).isOkOr:
    return err(FilterSubscribeError.serviceUnavailable(error))
  
  ok()

Exceptions still used for:

  • chronos async failures (CancelledError, etc.)
  • Database/system errors
  • Library interop

Most files start with {.push raises: [].} to disable exception tracking, then use try/catch blocks where needed.

Pragma Usage

{.push raises: [].}  # Disable default exception tracking (at file top)

proc myProc(): Result[T, E] {.async.} =  # Async proc

Protocol Inheritance

Protocols inherit from libp2p's LPProtocol:

type WakuLightPush* = ref object of LPProtocol
  rng*: ref rand.HmacDrbgContext
  peerManager*: PeerManager
  pushHandler*: PushMessageHandler

Type Visibility

  • Public exports use * suffix: type WakuFilter* = ...
  • Fields without * are module-private

Style Guide Essentials

This section summarizes key Nim style guidelines relevant to this project. Full guide: https://status-im.github.io/nim-style-guide/

Language Features

Import and Export

  • Use explicit import paths with std/ prefix for stdlib
  • Group imports: stdlib, external, internal (separate blocks)
  • Export modules whose types appear in public API
  • Avoid include

Macros and Templates

  • Avoid macros and templates - prefer simple constructs
  • Avoid generating public API with macros
  • Put logic in templates, use macros only for glue code

Object Construction

  • Prefer Type(field: value) syntax
  • Use Type.init(params) convention for constructors
  • Default zero-initialization should be valid state
  • Avoid using result variable for construction

ref object Types

  • Avoid ref object unless needed for:
    • Resource handles requiring reference semantics
    • Shared ownership
    • Reference-based data structures (trees, lists)
    • Stable pointer for FFI
  • Use explicit ref MyType where possible
  • Name ref object types with Ref suffix: XxxRef

Memory Management

  • Prefer stack-based and statically sized types in core code
  • Use heap allocation in glue layers
  • Avoid alloca
  • For FFI: use create/dealloc or createShared/deallocShared

Variable Usage

  • Use most restrictive of const, let, var (prefer const over let over var)
  • Prefer expressions for initialization over var then assignment
  • Avoid result variable - use explicit return or expression-based returns

Functions

  • Prefer func over proc
  • Avoid public (*) symbols not part of intended API
  • Prefer openArray over seq for function parameters

Methods (runtime polymorphism)

  • Avoid method keyword for dynamic dispatch
  • Prefer manual vtable with proc closures for polymorphism
  • Methods lack support for generics

Miscellaneous

  • Annotate callback proc types with {.raises: [], gcsafe.}
  • Avoid explicit {.inline.} pragma
  • Avoid converters
  • Avoid finalizers

Type Guidelines

Binary Data

  • Use byte for binary data
  • Use seq[byte] for dynamic arrays
  • Convert string to seq[byte] early if stdlib returns binary as string

Integers

  • Prefer signed (int, int64) for counting, lengths, indexing
  • Use unsigned with explicit size (uint8, uint64) for binary data, bit ops
  • Avoid Natural
  • Check ranges before converting to int
  • Avoid casting pointers to int
  • Avoid range types

Strings

  • Use string for text
  • Use seq[byte] for binary data instead of string

Error Handling

Philosophy

  • Prefer Result, Opt for explicit error handling
  • Use Exceptions only for legacy code compatibility

Result Types

  • Use Result[T, E] for operations that can fail
  • Use cstring for simple error messages: Result[T, cstring]
  • Use enum for errors needing differentiation: Result[T, SomeErrorEnum]
  • Use Opt[T] for simple optional values
  • Annotate all modules: {.push raises: [].} at top

Exceptions (when unavoidable)

  • Inherit from CatchableError, name XxxError
  • Use Defect for panics/logic errors, name XxxDefect
  • Annotate functions explicitly: {.raises: [SpecificError].}
  • Catch specific error types, avoid catching CatchableError
  • Use expression-based try blocks
  • Isolate legacy exception code with try/except, convert to Result

Common Defect Sources

  • Overflow in signed arithmetic
  • Array/seq indexing with []
  • Implicit range type conversions

Status Codes

  • Avoid status code pattern
  • Use Result instead

Library Usage

Standard Library

  • Use judiciously, prefer focused packages
  • Prefer these replacements:
    • async: chronos
    • bitops: stew/bitops2
    • endians: stew/endians2
    • exceptions: results
    • io: stew/io2

Results Library

  • Use cstring errors for diagnostics without differentiation
  • Use enum errors when caller needs to act on specific errors
  • Use complex types when additional error context needed
  • Use isOkOr pattern for chaining

Wrappers (C/FFI)

  • Prefer native Nim when available
  • For C libraries: use {.compile.} to build from source
  • Create xxx_abi.nim for raw ABI wrapper
  • Avoid C++ libraries

Miscellaneous

  • Print hex output in lowercase, accept both cases

Common Pitfalls

  • Defects lack tracking by {.raises.}
  • nil ref causes runtime crashes
  • result variable disables branch checking
  • Exception hierarchy unclear between Nim versions
  • Range types have compiler bugs
  • Finalizers infect all instances of type

Common Workflows

Adding a New Protocol

  1. Create directory: waku/waku_myprotocol/
  2. Define core files:
    • rpc.nim - Message types
    • rpc_codec.nim - Protobuf encoding
    • protocol.nim - Protocol handler
    • client.nim - Client API
    • common.nim - Shared types
  3. Define protocol type in protocol.nim:
    type WakuMyProtocol* = ref object of LPProtocol
      peerManager: PeerManager
      # ... fields
    
  4. Implement request handler
  5. Mount in WakuNode (waku/node/waku_node.nim)
  6. Add tests in tests/waku_myprotocol/
  7. Export module via waku/waku_myprotocol.nim

Adding a REST API Endpoint

  1. Define handler in waku/rest_api/endpoint/myprotocol/
  2. Implement endpoint following pattern:
    proc installMyProtocolApiHandlers*(
        router: var RestRouter, node: WakuNode
    ) =
      router.api(MethodGet, "/waku/v2/myprotocol/endpoint") do () -> RestApiResponse:
        # Implementation
        return RestApiResponse.jsonResponse(data, status = Http200)
    
  3. Register in waku/rest_api/handlers.nim

Adding Database Migration

For message_store (SQLite):

  1. Create migrations/message_store/NNNNN_description.up.sql
  2. Create corresponding .down.sql for rollback
  3. Increment version number sequentially
  4. Test migration locally before committing

For PostgreSQL: add in migrations/message_store_postgres/

Running Single Test During Development

# Build test binary
make test tests/waku_filter_v2/test_waku_client.nim

# Binary location
./build/tests/waku_filter_v2/test_waku_client.nim.bin

# Or combine
make test tests/waku_filter_v2/test_waku_client.nim "specific test name"

Debugging with Chronicles

Set log level and filter topics:

nim c -r \
  -d:chronicles_log_level=TRACE \
  -d:chronicles_disabled_topics="eth,dnsdisc" \
  tests/mytest.nim

Key Constraints

Vendor Directory

  • Never edit files directly in vendor - it is auto-generated from git submodules
  • Always run make update after pulling changes
  • Managed by nimbus-build-system

Chronicles Performance

  • Log levels are configured at compile time for performance
  • Runtime filtering is available but should be used sparingly: -d:chronicles_runtime_filtering=on
  • Default sinks are optimized for production

Memory Management

  • Uses refc (reference counting with cycle collection)
  • Automatically enforced by the build system (hardcoded in waku.nimble)
  • Do not override unless absolutely necessary, as it breaks compatibility

RLN Dependencies

  • RLN code requires a Rust toolchain, which explains Rust imports in some modules
  • Pre-built librln libraries are checked into the repository

Quick Reference

Language: Nim 2.x | License: MIT or Apache 2.0

Important Files

  • Makefile - Primary build interface
  • waku.nimble - Package definition and build tasks (called via nimbus-build-system)
  • vendor/nimbus-build-system/ - Status's build framework
  • waku/node/waku_node.nim - Core node implementation
  • apps/wakunode2/wakunode2.nim - Main CLI application
  • waku/factory/waku_conf.nim - Configuration types
  • library/libwaku.nim - C bindings entry point

Testing Entry Points

  • tests/all_tests_waku.nim - All Waku protocol tests
  • tests/all_tests_wakunode2.nim - Node application tests
  • tests/all_tests_common.nim - Common utilities tests

Key Dependencies

  • chronos - Async framework
  • nim-results - Result type for error handling
  • chronicles - Logging
  • libp2p - P2P networking
  • confutils - CLI argument parsing
  • presto - REST server
  • nimcrypto - Cryptographic primitives

Note: For specific version requirements, check waku.nimble.

GitNexus — Code Intelligence

This project is indexed by GitNexus as logos-delivery (2076 symbols, 2564 relationships, 12 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.

If any GitNexus tool warns the index is stale, run npx gitnexus analyze in terminal first.

Always Do

  • MUST run impact analysis before editing any symbol. Before modifying a function, class, or method, run gitnexus_impact({target: "symbolName", direction: "upstream"}) and report the blast radius (direct callers, affected processes, risk level) to the user.
  • MUST run gitnexus_detect_changes() before committing to verify your changes only affect expected symbols and execution flows.
  • MUST warn the user if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
  • When exploring unfamiliar code, use gitnexus_query({query: "concept"}) to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
  • When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use gitnexus_context({name: "symbolName"}).

Never Do

  • NEVER edit a function, class, or method without first running gitnexus_impact on it.
  • NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
  • NEVER rename symbols with find-and-replace — use gitnexus_rename which understands the call graph.
  • NEVER commit changes without running gitnexus_detect_changes() to check affected scope.

Resources

Resource Use for
gitnexus://repo/logos-delivery/context Codebase overview, check index freshness
gitnexus://repo/logos-delivery/clusters All functional areas
gitnexus://repo/logos-delivery/processes All execution flows
gitnexus://repo/logos-delivery/process/{name} Step-by-step execution trace

CLI

Task Read this skill file
Understand architecture / "How does X work?" .claude/skills/gitnexus/gitnexus-exploring/SKILL.md
Blast radius / "What breaks if I change X?" .claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md
Trace bugs / "Why is X failing?" .claude/skills/gitnexus/gitnexus-debugging/SKILL.md
Rename / extract / split / refactor .claude/skills/gitnexus/gitnexus-refactoring/SKILL.md
Tools, resources, schema reference .claude/skills/gitnexus/gitnexus-guide/SKILL.md
Index, status, clean, wiki CLI commands .claude/skills/gitnexus/gitnexus-cli/SKILL.md