
Ob Engineer
- 33 installs
- 2 repo stars
- Updated July 17, 2026
- ontoledgy/ol_ai_context_library
Helps with ai & agent building tasks.
About
ob-engineer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- ob-engineer
- AI & Agent Building
- AI-coding skill
Ob Engineer by the numbers
- 33 all-time installs (skills.sh)
- Ranked #8,944 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ontoledgy/ol_ai_context_library --skill ob-engineerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 33 |
|---|---|
| repo stars | ★ 2 |
| Last updated | July 17, 2026 |
| Repository | ontoledgy/ol_ai_context_library ↗ |
What it does
Helps with ai & agent building tasks.
Files
OB Engineer
Role
You are an OB (Ontoledgy/BORO) Python data engineer. You extend the python-data-engineer role with the BORO Quick Style Guide as the implementation standard.
Read `skills/python-data-engineer/SKILL.md` first and follow all of it. This file contains only the additions and overrides that apply to OB/BORO work.
---
Session Start — Determine Variant
Before any implementation or review work, read references/ob-library-selection.md and confirm the active variant:
| Variant | Platform Libraries | Signal |
|---|---|---|
| BORO | nf_common | Codebase imports nf_common |
| Ontoledgy | bclearer_pdk, ai, ui | Codebase imports these libraries |
Use the active variant's platform libraries throughout. All BORO coding conventions are identical across both variants.
---
Additional References
| Reference | Content |
|---|---|
references/boro-quick-style-guide.md | Full BORO Quick Style Guide — naming, layout, structure, error handling |
references/ob-library-selection.md | Variant → platform library mapping |
---
BORO Overrides to python-data-engineer
Where BORO and python-data-engineer (PEP 8) conflict, BORO wins. The key overrides:
| Dimension | python-data-engineer | BORO override |
|---|---|---|
| Line length | PEP 8: 79 chars | 20 chars |
| Class names | Singular CamelCase | Plural CamelCase (MyObjectTypes) |
| File structure | One responsibility per file | One public function per file |
| Private methods | _single_underscore | `__double_underscore` (note: triggers name mangling in classes) |
| Named parameters | Best practice | Mandatory — use * to enforce |
| Type annotations | Encouraged | Mandatory — all params + return types |
| Strings | No hardcoding | Mandatory — all strings in constants or enums |
| Import style | Clean imports | Explicit only — no *, no folder imports |
| Platform library | General DRY | Check active variant's library first |
| File/folder ops | os/pathlib | Use platform library (see ob-library-selection.md) |
| File naming | Descriptive | Actor names aligned with public function |
| Orchestration | General pattern | *`orchestrate_() in _orchestrator.py`* |
| Error handling | Use exceptions | Specific exceptions only — no except Exception: |
| Comments | Minimal | None — code must be self-documenting |
Full rule set is in references/boro-quick-style-guide.md.
---
Implement Mode Additions
Before implementing any feature:
1. Confirm variant from ob-library-selection.md 2. Check platform library — does the active variant already have a function for this? 3. Plan module structure — one public function per file; orchestrators in *_orchestrator.py 4. Apply BORO naming from the start — do not name and rename later
Implementation order follows python-data-engineer (read spec → read existing code → implement in construction order → write tests → verify). Apply the BORO checklist at each step.
---
Review Mode Additions
When reviewing OB code, apply the full python-data-engineer review checklist and add the BORO-specific checks:
| Check | Pass criteria |
|---|---|
| Class names plural | class MyObjectTypes: not class MyObjectType: |
| File = actor, function = action | data_exporter.py with export_data() public function |
| One public function per file | Only exception: facade files |
__ private methods | Not _ in Python files |
| Named parameters enforced | * in function signatures at module boundaries |
| All types annotated | Params + return type on every public function |
| No hardcoded strings | All strings in constants/enums |
| Single quotes | String delimiter is ', not " |
| Explicit imports only | No from x import *; no import folder.subfolder |
| Platform library used | Active variant's library used for file/folder/utility ops |
No bare except | Only named exception types; bare raise to preserve traceback |
| No comments | Only # TODO or development notes permitted |
Use violation severity from boro-quick-style-guide.md implementation checklist:
- HIGH: Missing type annotations; hardcoded strings; bare
except; wrong platform library - MEDIUM: Naming violations; missing
__on private methods; non-actor file names - LOW: Line length; missing named parameters; single vs double quotes
---
OB Quality Gates
Run after every implementation, in addition to the python-data-engineer quality gates:
ruff check src/ # linting
ruff format src/ # formatting (note: 20-char lines require manual line-break discipline)
mypy src/ --strict # type checking — strict mode required for OB (all types must be present)
pytest # all tests passNote: ruff's default line length is 88 characters. BORO's 20-character limit is enforced by discipline and review, not the formatter. Do not override ruff's line-length setting — the 20-char rule applies to logical statements, not tool configuration.
BORO Quick Style Guide — Rust
The implementation standard for OB (Ontoledgy/BORO) Rust codebases. This guide overrides rust-data-engineer defaults where they conflict. Rules not covered here fall back to rust-data-engineer standards.
Derived from the Python BORO Quick Style Guide (boro-quick-style-guide.md), translating each principle to idiomatic Rust while preserving the same design philosophy: precision, self-documentation, and strict separation of concerns.
Source: BORO/Ontoledgy Confluence space — BORO Clean Coding sections (pages 6495863472, 6495863609, 6495863620, 6495862997, 6495863571).
---
Naming Conventions
| Symbol | BORO Standard | Rust / rust-data-eng default | Notes |
|---|---|---|---|
| Struct/enum names | PascalCase, plural | PascalCase, singular | struct ObjectTypes {} |
| Trait names | PascalCase, plural or verb | PascalCase | trait Exportable {} or trait ObjectFormatters {} |
| Module/file names | snake_case, actor names aligned with public function | snake_case, descriptive | data_exporter.rs → pub fn export_data() |
| Constant names | UPPER_SNAKE_CASE | UPPER_SNAKE_CASE | Compatible |
| All other names | snake_case | snake_case | Compatible |
| Function names | action verbs | verbs recommended | get_something(), export_data() |
| Boolean functions | is_ or has_ prefix | is_ recommended | Mandatory in BORO |
| Private functions | fn (no pub) — module-private only | fn or pub(crate) | BORO: never pub(crate) for internal helpers; visibility is fn (module-private) or pub (public API) |
| Forbidden names | process, handle, data, item, tmp, res, unclear abbreviations | — | Strictly forbidden |
| Forbidden single letters | All except self | Loop indices allowed | BORO overrides — no i, j, k, n, x |
| File rename rule | If public function renamed → file must be renamed | — | BORO-specific rule |
Deeper Naming Principles
- Use intention-revealing names — precision over brevity
- Avoid disinformation — don't imply wrong meaning
- Make meaningful distinctions — adjacent things must be distinguishable
- Use pronounceable, searchable names
- Avoid encodings (no type prefixes, no Hungarian notation)
- Struct/enum names = plural nouns; avoid
Manager,Processor,Data,Info - Method names = verbs or verb phrases; accessors use
get_/set_/is_ - No mental mapping, no slang, no culture-specific terms
- One word per concept — consistency across sibling methods and structs
---
Code Layout
| Rule | BORO Standard | Rust default | Notes |
|---|---|---|---|
| Line length | 20 chars | 100 chars (rustfmt) | BORO overrides — intentional; enforced by discipline, not rustfmt |
| Between statements | One empty line | — | BORO-specific |
After opening { | Do NOT leave next line empty | — | BORO-specific |
| Variable bindings | One let per line; never chain assignments | one per line | BORO-specific emphasis |
| Function arguments | Each argument on its own line | flexible | BORO-specific |
| Struct field args | Use struct construction for > 3 params; name every field at construction site | best practice | Mandatory in BORO — Rust has named fields by default; always use them |
| Type annotations | Compiler-enforced for function signatures; add explicitly on let bindings when type is not obvious from the right-hand side | inferred where possible | BORO adds explicit let annotation discipline |
| Return type | Always specified in function signature; -> () if nothing returned (do not omit) | omit for () | BORO overrides — explicit -> () |
| For loops | Iterator body on new line after `.for_each(\ | item\ | or for item in` on separate line from collection |
| Impl block member sequence | constants → associated functions (constructors) → getters/setters → methods → trait impls | — | BORO-specific |
| Indentation | 4 spaces; no TABs | 4 spaces | Compatible |
| Related fields | No empty line between them; empty line between unrelated field groups | — | BORO-specific |
---
Function Design
| Rule | BORO Standard |
|---|---|
| Return | Only one value (use a named struct if multiple values needed — no raw tuples in public APIs) |
| Responsibility | One thing only — strict separation of concerns |
| Decomposition | Break into sub-functions as much as possible |
| Too many arguments | Create a config/params struct to pass them (> 3 params) |
| Flag arguments | Forbidden — use enums with meaningful variant names |
| Private functions | Module-private fn — called only by the module's public function; never pub(crate) for internal helpers |
| Exposing behaviour | If external code needs it → promote to pub fn in the module's public API |
| Closures | Extract closures > 1 expression into named private functions |
| Method chains | Break chains > 3 links into named intermediate let bindings |
---
File / Module Structure
| Rule | BORO Standard |
|---|---|
| Per-file rule | One `pub fn` (entry point) + its private helper functions |
| Exception | Facade modules may re-export multiple public items |
| Orchestrator pattern | When managing a sequence of stages → use pub fn orchestrate_*() |
| Orchestrator file name | *_orchestrator.rs |
| Orchestrator function name | orchestrate_*() |
| Nesting | Orchestrators can be nested |
mod.rs / module directories | Use module_name.rs (not module_name/mod.rs) — Rust 2018+ edition style |
| Re-exports | Only in facade/lib.rs; explicit pub use (never pub use crate::module::*) |
---
Type Design (Structs, Enums, Traits)
| Rule | BORO Standard |
|---|---|
| Struct names | Plural PascalCase (ObjectTypes, TransactionRecords) |
| Enum names | Plural PascalCase; variants are singular PascalCase (enum OutputFormats { Csv, Json }) |
| Trait names | PascalCase; verb/adjective forms preferred (Exportable, Validatable) |
| Instance methods | &self or &mut self — prefer &self (immutable borrow) |
No self usage | Associated function (like Python's @staticmethod): fn new(), fn from_*() |
| Constructors | fn new() for primary; fn from_*() for conversions; fn try_new() / fn try_from_*() when fallible |
| Derive macros | #[derive(Debug)] mandatory on all types; add Clone, PartialEq only when semantically meaningful |
| Tuple structs | Forbidden in public APIs — use named fields for self-documentation |
| Raw tuples | Forbidden in function returns and public APIs — use named structs |
| Field visibility | Private by default; expose with getter methods, not pub fields |
---
Constants and Strings
| Rule | BORO Standard |
|---|---|
| Hardcoded strings | Never — define as const or enum variants |
| Constants location | Separate constants.rs module |
| Enums | Separate module per domain enum |
| File/folder paths | Use std::path::Path / PathBuf; construct with .join() |
| String type | Use &str for borrowing, String for ownership; never &String in function params |
| Magic numbers | Forbidden — all numeric literals as named const values |
---
Error Handling
| Rule | BORO Standard |
|---|---|
| Error types | Domain-specific error enums with thiserror — one error enum per module boundary |
| Generic errors | Forbidden: no Box<dyn Error>, no anyhow::Error in library/domain code (anyhow only in binary entry points) |
.unwrap() | Forbidden in production code — use ? operator |
.expect() | Only when the invariant is provably true; message must document the invariant (e.g. .expect("config validated at startup")) |
| Error context | Every ? propagation at a boundary must add context (.map_err() or thiserror #[from]) |
| Panic | Forbidden in library code — only in binary entry points or test code |
todo!() / unimplemented!() | Allowed during development; forbidden in merged code |
---
Ownership and Borrowing
These rules have no Python equivalent — they are Rust-specific BORO additions derived from the same design philosophy (precision, no waste, explicit contracts).
| Rule | BORO Standard |
|---|---|
| Prefer borrowing | &T over T unless ownership transfer is semantically required |
| Clone discipline | Never clone to satisfy the borrow checker — restructure ownership instead; Clone only when the domain requires independent copies |
| Lifetime annotations | Explicit when not elidable; name them meaningfully ('record, 'config, not 'a, 'b) |
Arc/Rc | Only for genuine shared ownership (documented in a comment why shared); never as a convenience to avoid restructuring |
Box<dyn Trait> | Only when runtime polymorphism is required (heterogeneous collections); prefer generics with trait bounds for static dispatch |
unsafe | Forbidden unless architecturally approved and documented with // SAFETY: comment explaining the invariant |
Copy types | Derive Copy only for small, semantically value-like types (IDs, flags, coordinates) |
| Interior mutability | Cell/RefCell/Mutex only when mutation through shared reference is architecturally necessary; document why |
---
Imports / use Statements
| Rule | BORO Standard |
|---|---|
| Import style | Explicit: use crate::module::TypeName; |
| Glob imports | Forbidden: no use crate::module::*; (exception: test preludes in #[cfg(test)]) |
| Re-exports | Only in facade modules / lib.rs; explicit pub use |
| External crates | Group and separate from internal imports with an empty line |
use ordering | std → external crates → crate:: → super:: → self:: |
| Nested paths | Prefer flat imports over deeply nested use trees for readability |
---
Comments
| Rule | BORO Standard |
|---|---|
| General comments | Code must not need comments — self-documenting names and structure |
Doc comments (///) | Mandatory on every pub item — one sentence explaining what, not how |
| Internal comments | Forbidden except // TODO and // SAFETY: (for approved unsafe) |
//! module docs | One sentence at the top of each module file stating the module's actor responsibility |
---
Iterator and Loop Design
| Rule | BORO Standard |
|---|---|
| Prefer iterators | Use .iter() / .into_iter() chains over for loops where the chain reads naturally |
| Iterator body > 1 expression | Extract .map() / .filter() / .for_each() closure into a named private function |
| Nested iteration | Must NOT be visible — extract inner loop into a private function |
for loop in clause | Collection expression on a new line if it doesn't fit on one line |
.collect() | Always annotate the target type: .collect::<Vec<_>>() or bind to a typed let |
| Index access | Forbidden in iteration — use .iter(), .enumerate(), or .windows() |
---
Concurrency (Rust-Specific BORO Addition)
| Rule | BORO Standard |
|---|---|
| Async runtime | tokio — do not mix runtimes |
async fn | Same function design rules apply — one responsibility, decompose aggressively |
| Channels | Prefer typed channels (tokio::sync::mpsc) over shared mutable state |
Mutex/RwLock | Only when channels don't fit; hold locks for the shortest possible scope; extract locked operations into a function |
| Spawned tasks | Each spawned task gets a named function — never inline large closures in tokio::spawn() |
---
Best Practices
| Principle | Rule |
|---|---|
| YAGNI | Don't write code you don't need yet |
| DRY — Rule of Three | Third time you write the same code → extract to a helper |
| Fail Fast | Validate input at module boundaries; return Err on invalid state immediately |
| API Design | Simple things should be simple; complex things should be possible |
| Compiler as Ally | If the compiler can enforce an invariant (types, visibility, lifetimes), let it — don't add runtime checks for compile-time guarantees |
| Zero-Cost Abstractions | Prefer generics over trait objects; prefer stack over heap; prefer borrowing over cloning |
---
Quality Gates
Run after every implementation:
cargo build # compilation
cargo clippy -- -D warnings # lint — all warnings are errors
cargo fmt --check # formatting (note: 20-char line limit is discipline, not rustfmt config)
cargo test # all tests pass
cargo doc --no-deps # doc comments compile and link correctlyNote: rustfmt's default max_width is 100 characters. BORO's 20-character limit is enforced by discipline and review, not the formatter. Do not override rustfmt's line-width setting — the 20-char rule applies to logical statements, not tool configuration.
---
Implementation Checklist
Use this checklist when implementing or reviewing OB Rust code.
Naming
- [ ] Structs/enums: PascalCase, plural (
ObjectTypes,OutputFormats) - [ ] Enum variants: singular PascalCase (
OutputFormats::Csv) - [ ] Modules/files: snake_case, actor name matching public function
- [ ] Functions: action verbs (
get_,export_,orchestrate_) - [ ] Private functions:
fn(nopub), module-private only - [ ] Constants:
UPPER_SNAKE_CASE - [ ] Booleans:
is_orhas_prefix - [ ] No vague names: no
data,tmp,process,handle,res - [ ] No single-letter names except
self - [ ] Lifetime names: meaningful words, not single letters (
'record, not'a)
Layout
- [ ] Lines: ≤ 20 characters (logical statements)
- [ ] Function args: each on its own line
- [ ] Explicit
-> ()return type (never omitted) - [ ] Explicit type annotations on
letbindings where type is non-obvious - [ ] Struct construction: name every field at construction site
- [ ] One empty line between statements
- [ ] No empty line after opening
{
Structure
- [ ] One
pub fnper file (module) - [ ] Orchestrators in
*_orchestrator.rsfiles - [ ] Private functions: only called by the module's public function
- [ ] No
pub(crate)for internal helpers — usefn(module-private) - [ ] Associated functions for constructors (
new,from_*,try_new) - [ ] Module style:
module_name.rs(notmodule_name/mod.rs)
Types
- [ ]
#[derive(Debug)]on all types - [ ] No tuple structs in public API — named fields only
- [ ] No raw tuples in function returns — named structs
- [ ]
Cloneonly when domain semantics require it - [ ] Private fields with getter methods (no
pubfields)
Constants and Strings
- [ ] No hardcoded strings — all in
constor enum variants - [ ] No magic numbers — named
constvalues - [ ] Paths use
Path/PathBufwith.join() - [ ]
&strfor borrowing,Stringfor ownership; never&Stringin params
Error Handling
- [ ] Domain error enums with
thiserror - [ ] No
Box<dyn Error>in domain code - [ ] No
.unwrap()in production code - [ ]
.expect()only with documented invariant - [ ]
?with.map_err()context at boundaries - [ ] No
panic!in library code
Ownership
- [ ] Borrow (
&T) unless ownership transfer is required - [ ] No cloning to satisfy borrow checker
- [ ] Meaningful lifetime names
- [ ]
unsafeonly with approval +// SAFETY:comment
Imports
- [ ] Explicit
use— no glob imports (except test preludes) - [ ] Order:
std→ external →crate→super→self - [ ] Re-exports only in facade /
lib.rs
Comments
- [ ]
///doc comments on everypubitem - [ ]
//!module doc at top of each file - [ ] No internal comments except
// TODOand// SAFETY:
Iteration
- [ ] Iterators preferred over
forloops - [ ] Closure body > 1 expression → named function
- [ ] No visible nested iteration
- [ ] No index access in loops — use
.iter()/.enumerate() - [ ]
.collect()always type-annotated
BORO Quick Style Guide
The implementation standard for OB (Ontoledgy/BORO) Python codebases. This guide overrides PEP 8 and python-data-engineer defaults where they conflict. Rules not covered here fall back to python-data-engineer standards.
Source: BORO/Ontoledgy Confluence space — BORO Clean Coding sections (pages 6495863472, 6495863609, 6495863620, 6495862997, 6495863571).
---
Naming Conventions
| Symbol | BORO Standard | PEP 8 / py-data-eng default | Notes |
|---|---|---|---|
| Class names | CamelCase, plural | CamelCase, singular | class MyObjectTypes: |
| Class file names | snake_case | snake_case | Compatible |
| Constant names | CAPITAL_CASE | UPPER_SNAKE_CASE | Compatible |
| All other names | snake_case | snake_case | Compatible |
| Function names | action verbs | verbs recommended | get_something(), export_data() |
| File names | actor names aligned with public function | descriptive | data_exporter.py → export_data() |
| Boolean functions | is_ or has_ prefix | is_ recommended | Mandatory in BORO |
| Private methods | `__double_underscore` | _single_underscore | BORO overrides PEP 8 |
| String delimiter | single quotes only | either | 'example string' |
| Forbidden names | process, handle, data, item, tmp, res, unclear abbreviations | — | Strictly forbidden |
| Forbidden single letters | All except self, cls | Loop indices allowed | BORO overrides |
| File rename rule | If public function renamed → file must be renamed | — | BORO-specific rule |
Deeper Naming Principles
- Use intention-revealing names — precision over brevity
- Avoid disinformation — don't imply wrong meaning
- Make meaningful distinctions — adjacent things must be distinguishable
- Use pronounceable, searchable names
- Avoid encodings (no type prefixes)
- Class names = plural nouns; avoid
Manager,Processor,Data,Info - Method names = verbs or verb phrases; accessors use
get_/set_/is_ - No mental mapping, no slang, no culture-specific terms
- One word per concept — consistency across sibling methods and classes
---
Code Layout
| Rule | BORO Standard | PEP 8 default | Notes |
|---|---|---|---|
| Line length | 20 chars | 79 chars | BORO overrides PEP 8 — intentional |
| Between instructions | One empty line | — | BORO-specific |
After colon : (function/loop) | Do NOT leave next line empty | — | BORO-specific |
| Variable assignments | Always on new line after backslash \ | implicit continuation | BORO uses backslash |
| Function arguments | Each argument on its own line; no spaces around = in calls | flexible | BORO-specific |
| Named parameters | Always specify argument name at call site; use * to enforce | best practice | Mandatory in BORO |
| Type annotations | Always specify all parameter types | encouraged | Mandatory in BORO |
| Return type | Always specified, on new line before colon; -> None if nothing returned | encouraged | Mandatory in BORO |
| For loops | in block goes on a new line | — | BORO-specific |
| Class member sequence | constants → static attrs → object attrs → inner classes → getters/setters → methods | — | BORO-specific |
| Indentation | 4 spaces; no TABs | 4 spaces | Compatible |
| Related attributes | No empty line between them; empty line between all other members | — | BORO-specific |
---
Function Design
| Rule | BORO Standard |
|---|---|
| Return | Only one item |
| Responsibility | One thing only — strict separation of concerns |
| Decomposition | Break into sub-functions as much as possible |
| Too many arguments | Create a class to pass them |
| Flag arguments | Forbidden |
| Private functions | Called only by the file's public function; never called externally |
| Exposing behaviour | If external code needs it → expose as a public method |
---
File / Module Structure
| Rule | BORO Standard |
|---|---|
| Per-file rule | One public (entry point) function + its private subfunctions |
| Exception | Facade/suite files may have multiple related public functions |
| Orchestrator pattern | When managing a sequence of processes → use orchestrate_*() function |
| Orchestrator file name | [name]_orchestrator.py |
| Orchestrator function name | orchestrate_[name]() |
| Nesting | Orchestrators can be nested |
---
Class Design
| Rule | BORO Standard |
|---|---|
| Instance methods | Use self |
No self/cls usage | Declare as @staticmethod |
| Class-level methods | Use @classmethod (e.g. bie_identity_type(cls)) |
---
Constants and Strings
| Rule | BORO Standard |
|---|---|
| Hardcoded strings | Never — define as constants or enums |
| Constants location | Separate file(s) |
| Enums | Separate class |
| File/folder paths | Use os.path.join() and os.sep; use Path() constructor |
---
Error Handling
| Rule | BORO Standard |
|---|---|
| Catch specificity | Only specific exceptions — never bare except: or except Exception: |
| Traceback preservation | Use bare raise inside except |
| Unimplemented | raise NotImplementedError is allowed |
---
Library Usage
Always read ob-library-selection.md first to confirm the correct platform libraries for the current codebase variant.
| Rule | BORO variant | Ontoledgy variant |
|---|---|---|
| File/folder operations | nf_common Files and Folders | bclearer_pdk equivalents |
| General utilities | Check nf_common first | Check bclearer_pdk, ai, ui first |
The following rules apply to both variants:
| Rule | Standard |
|---|---|
| Import style | Explicit only: from file import class/method/constant |
| Wildcard imports | Forbidden: from x import * |
| Folder imports | Forbidden: import folder_a.folder_b |
---
Comments
| Rule | BORO Standard |
|---|---|
| General comments | Clean code must not need comments |
| Code self-documentation | Code should be clear and self-explanatory |
| Allowed comments | Development purposes only: # TODO, development notes |
---
Loop Design
| Rule | BORO Standard |
|---|---|
| Loop body > 1 statement | Extract all loop content into a private function |
| Nested loops | Must NOT be visible — group into private functions |
for loop in clause | Goes on a new line |
---
Best Practices
| Principle | Rule |
|---|---|
| YAGNI | Don't write code you don't need yet |
| DRY — Rule of Three | Third time you write the same code → extract to a helper |
| Fail Fast | Validate input; fail on invalid state as early as possible |
| API Design | Simple things should be simple; complex things should be possible |
---
Implementation Checklist
Use this checklist when implementing or reviewing OB code.
Naming
- [ ] Classes: CamelCase, plural
- [ ] Files: snake_case, actor name matching public function
- [ ] Functions: action verbs (
get_,export_,import_,orchestrate_) - [ ] Private functions:
__double_underscore - [ ] Constants:
CAPITAL_CASE - [ ] Booleans:
is_orhas_prefix - [ ] No vague names: no
data,tmp,process,handle,res
Layout
- [ ] Lines: ≤ 20 characters
- [ ] Function args: each on its own line
- [ ] Type annotations: all parameters declared
- [ ] Named parameters: enforced with
* - [ ] Return type: declared on new line before
: - [ ] Variable assignments: new line after
\ - [ ] For loops:
inblock on new line - [ ] One empty line between instructions
Structure
- [ ] One public function per file
- [ ] Orchestrators in
*_orchestrator.pyfiles - [ ] Private functions: only called by the file's public function
- [ ]
@staticmethodwhere noself/clsneeded - [ ]
@classmethodfor class-level identity methods
Strings and Constants
- [ ] No hardcoded strings — all in constants/enums
- [ ] Paths use
os.path.join()+os.seporPath() - [ ] String delimiter: single quotes
Error Handling
- [ ] Specific exceptions only — named exception types
- [ ] Bare
raiseto preserve traceback - [ ] No
except:orexcept Exception:
Libraries
- [ ] Active variant's platform library checked before writing general functions
- [ ] Imports:
from file import nameonly - [ ] No
from x import * - [ ] No folder-level imports
Comments
- [ ] No comments unless
# TODO/ development note
OB Library Selection
How to Determine the Active Variant
Read the codebase's dependency declarations (e.g. requirements.txt, pyproject.toml):
| Signal | Variant |
|---|---|
Imports or depends on nf_common | BORO — codebase is in a bCLEARer project |
Imports or depends on bclearer_pdk, ai, or ui | Ontoledgy — codebase is in the Ontoledgy repo |
When uncertain, ask the user which variant applies before proceeding.
---
BORO — Platform Libraries
| Function | Library | Class / Function |
|---|---|---|
| File operations | nf_common | Files |
| Folder operations | nf_common | Folders |
| General utilities | nf_common | Check the full catalogue before writing new utility code |
Dependency declaration: add nf_common to requirements.txt or pyproject.toml.
---
Ontoledgy — Platform Libraries
| Function | Library | Class / Function |
|---|---|---|
| Core PDK utilities | bclearer_pdk | Check the full catalogue before writing new utility code |
| AI capabilities | ai | Check the full catalogue before writing new AI-related code |
| UI components | ui | Check the full catalogue before writing new UI code |
Dependency declaration: add bclearer_pdk, ai, and/or ui as required.
---
Rule
Always check the active variant's platform library catalogue before writing a new utility function. Custom code is only justified when no platform function covers the need.
Both variants share the same BORO coding conventions (naming, layout, structure, error handling). Only the platform library references differ.