This repository provides eBPF-based instrumentation for applications and integrates with OpenTelemetry.
Agents operating on this repository must produce small, correct, and reviewable changes that respect the existing architecture and development workflow.
For an overview of the data pipeline and component relationships, start with devdocs/pipeline-map.md. If DeepWiki MCP is configured in the agent environment, agents may also consult the DeepWiki repository page for additional architecture and codebase context.
When repository files do not fully answer a question, prefer these references:
Prefer repository code and local documentation when there is any discrepancy with external references or summaries.
bpf/ eBPF C programs, maps, and shared headers
bpfcore/ vmlinux.h and BPF core helpers
common/ Shared headers (scratch_mem.h, pin_internal.h, …)
maps/ Map definitions shared across programs
<subsystem>/ One directory per eBPF program (generictracer, gotracer, tpinjector, …)
cmd/ Go binary entry points (obi, k8s-cache, …)
pkg/ Public Go packages
pkg/internal/ Internal Go packages; ebpf/ subdirectory holds per-subsystem loaders
internal/ Integration test infrastructure
test/integration/ Integration tests
configs/ Example and default configuration files
Generated files (never edit manually):
*_bpfel.go,*_bpfeb.go— Go bindings produced bybpf2gofrom eBPF C source*_bpfel.o,*_bpfeb.o— Compiled eBPF bytecodebpf/bpfcore/— Copied and auto-generated files; do not edit anything in this directory
Do not assume boundaries can be changed without explicit instruction.
- Keep changes minimal and scoped to the task.
- Do not include unrelated edits, formatting changes, or cleanup.
- Follow existing code patterns and structure.
- Prefer consistency with surrounding code over stylistic changes.
- Do not introduce unnecessary abstractions.
- Refactors are allowed only when they are directly relevant to the task.
If the task is unclear or underspecified, ask for clarification before making changes.
Write issue and pull request descriptions, reviews, and comments for human readers. Keep them concise, specific, and easy to scan. Lead with the relevant point, use short paragraphs or lists when helpful, and include only the context needed to understand or act on the message. Do not post generated wall-of-text reports, exhaustive restatements of the code, or a play-by-play of the work.
Before proposing changes, ensure the repository generates required artifacts, passes validation, and compiles successfully.
Preferred validation targets:
make verifyfor the main validation flowmake buildwhen generation and compilation are also requiredmake generateormake docker-generatewhen any.cfile inbpf/is added or modified
Use make lint, make test, and make compile for targeted iteration when a full validation run is unnecessary.
For Markdown-only changes, run make lint-markdown.
C code must be formatted and linted before proposing changes. Run make install-hooks to install pre-commit hooks that enforce this automatically, or run make clang-format and make clang-tidy manually.
Integration tests live in internal/test/integration/:
go test -v -run <TestName> -timeout 10m ./internal/test/integration/
Do not propose changes that fail local validation.
OBI publishes an OpenTelemetry telemetry schema under site/schemas/obi/ and
emits a schema_url on its telemetry. Cutting a new version and bumping the
emitted URL (OBISchemaURL) are automated at release prep (make prerelease runs
make generate-schema-next), and make check-schema-files guards their
consistency in CI.
Reference docs for what OBI emits are rendered from the same registry into
site/docs/ by make generate-schema-docs, which make prerelease also runs so
each release ships docs matching its registry. Between releases, rerun it and
commit the result whenever the registry changes; it is not verified in CI.
The one step that is not automated: recording renames or removals of emitted
attributes or metrics as schema transformations. If a change renames or removes
emitted telemetry, it must be recorded so consumers can convert across versions —
add the transformation to the next schema version's block at release prep, per the
procedure in devdocs/telemetry-schema.md ("Releasing a new version"). This cannot be enforced
mechanically today, so it is the contributor's and release owner's responsibility.
These rules apply to all code in the repository.
- Clarity is paramount. Code must be easy to read and reason about.
- Prefer simple, explicit logic over clever or compact code.
- Design code to be orthogonal. Changes in one area must not introduce side effects in unrelated parts of the system.
- Avoid overlapping responsibilities. Each component should do one thing and do it well.
- Prefer composition of small, independent pieces over tightly coupled logic.
- Do not introduce hidden coupling between components.
- Functions must be small and focused. Split large functions when needed.
- Maintain clear structure and naming. Prioritize readability over brevity.
- Prefer early returns when they improve readability and reduce indentation depth.
- Use vertical spacing to separate logical blocks and improve readability. Do not compress unrelated logic into a dense block of code.
- Do not use magic numbers. Name constants or derive sizes from existing types and objects when possible.
- Do not introduce new implementations when equivalent functionality already exists in the repository or its dependencies. Search for and reuse existing utilities, helpers, or patterns — including those provided by external libraries already in use. Extend or adapt existing code instead of duplicating functionality.
Comments must be minimal:
- Do not add comments that restate the code.
- Prefer clearer code over explanatory comments.
- Add comments only when they provide necessary context, explain non-obvious behavior, or document verifier, kernel, or ABI constraints.
- Avoid unnecessary interfaces. Do not introduce interfaces unless they are needed for an existing design boundary, multiple implementations, or tests.
- Avoid over-abstraction. Prefer concrete types and straightforward code.
- Do not introduce new layers, wrappers, or indirection without a clear need.
- Respect existing package boundaries and responsibilities.
- Apply modern C best practices with readability and maintainability as the priority.
- Prefer
constcorrectness wherever possible. - Use the narrowest appropriate integer type. Prefer unsigned types for sizes, counts, indexes, bitfields, and values that cannot be negative. Use signed types only when signed semantics are required.
- Prefer enums over macros for constants. Avoid macros unless they are strictly necessary.
- Use
sizeof(*ptr)when it improves correctness and maintainability. - Prefer deriving sizes with
sizeofover introducing separate size constants when the size can be obtained directly from the object or type. - Buffers and raw memory chunks must use
unsigned char *, notu8 *. - Initialize variables as locally as possible and keep their lifetime narrow.
- Maps that are not explicitly pinned for external use must default to
OBI_PIN_INTERNAL(defined inbpf/common/pin_internal.h). - Use
SCRATCH_MEM,SCRATCH_MEM_TYPED, andSCRATCH_MEM_SIZEDfor scratch memory patterns instead of introducing ad hoc temporary buffers (defined inbpf/common/scratch_mem.h). - For tail calls, prefer
bpf_tail_call_static(...). Define tail call program arrays in the eBPF C code unless there is a clear reason not to. - Use
bpf_probe_read_kernelfor kernel memory,bpf_probe_read_userfor user memory, and default tobpf_probe_readonly when writing genuinely generic code that must handle both cases. - OBI requires kernel 5.8 or higher with BTF enabled. RHEL-based distributions (RHEL8, CentOS 8, Rocky8, AlmaLinux8) are supported via kernel 4.18 with backported eBPF patches. Do not use helpers or features unavailable in the minimum supported kernel unless gated by a runtime check.
- Respect verifier limitations and kernel compatibility.
- Avoid patterns that increase verifier complexity or risk rejection.
- Keep programs simple and predictable.