Skip to main content

5 posts tagged with "Developer Experience"

Improving the developer workflow with better tooling and patterns

View All Tags

Building an AI-Ready Codebase: Architecture Decisions That Pay Off

· 5 min read
Gabriel Paunescu
Founder CTO Neologic

Your architecture is your AI strategy. Every decorator, every naming convention, every file-per-function decision determines whether AI can contribute meaningfully to your codebase — or just generate noise.

The Premise

Most teams try to adopt AI coding assistants by writing better prompts. Logic Bee took a different approach: redesign the architecture so AI can't get it wrong. One hook per file. Mandatory decorators with machine-readable metadata. Self-registering modules. The result? AI agents that understand the codebase as well as a new team member — on day one.

The Story

When Logic Bee was a monolithic Express app, AI code generation was unreliable. Functions were tangled across large files. Business logic mixed with routing. Naming was inconsistent. An AI asked to "add a billing function" would generate code that worked in isolation but broke in context.

The refactoring to a decorator-based, one-hook-per-file architecture wasn't about AI. It was about maintainability, testability, and developer experience. But the side effect was transformative: the same codebase that became easier for humans to navigate also became trivially parseable by AI.

The Five Decisions

1. One Function, One File

Every hook lives in its own file at a predictable path:

hooks/{library-slug}/{method-slug}/{method-slug}.{library-slug}.hook.ts

Why it matters for AI: When the AI generates a new hook, it never needs to decide where to put the code. The path is deterministic from the library and method names. There's no risk of the AI inserting code into the wrong file or appending to an existing module.

Why it matters for humans: Code reviews are self-contained. git diff shows one function per file. Merge conflicts between developers working on different hooks are eliminated.

2. Self-Describing Decorators

Every hook wears its identity on its sleeve:

@LogicHook({
name: 'FinanceBillsCalculateLateFees',
path: 'finance-bills/calculate-late-fees',
library: 'finance-bills',
method: 'calculate-late-fees'
})

Why it matters for AI: The decorator is structured metadata — not a comment, not documentation, but code that the system reads at boot time. AI can scan decorators to understand what a hook does without reading the business logic.

Why it matters for humans: New developers can grep for any hook by name, library, or method. Discovery is instant.

3. Auto-Generated Barrels

When a new hook is created, barrel files (index.ts) are regenerated automatically. Developers never manually import hooks.

Why it matters for AI: The AI can scaffold a hook, run the barrel generator, and know that the hook is registered — without understanding the module system. No manual import means no forgotten imports.

Why it matters for humans: One less thing to remember. One less source of "it compiles but doesn't run" bugs.

4. Standardized Wrapper Pattern

Every hook uses the Bob Wrapper: execute()async (bob) =>try/catchreturnEventResult.

public static execute() {
return async (bob: BobRequest<T>) => {
let ok = true, error: any = null, data
try {
// business logic
} catch (err) { error = err; ok = false }
return returnEventResult(bob, { ok, error, data })
}
}

Why it matters for AI: The wrapper is a rigid template. AI fills in the business logic between START_CODE_LOGIC and END_CODE_LOGIC. The structural code around it is identical across hundreds of hooks — which means the AI never gets it wrong.

Why it matters for humans: Every hook reads the same way. Error handling is guaranteed. The cognitive load of reading unfamiliar code drops to near zero.

5. Machine-Readable Skills

Business rules, conventions, and patterns are encoded in .agents/skills/ — not in wiki pages, Slack threads, or tribal knowledge.

Why it matters for AI: Skills are loaded at prompt time. The AI doesn't need to infer conventions from code samples — it reads the rules directly.

Why it matters for humans: Skills are versioned with the codebase. When conventions change, the skill files update, and the AI immediately adapts.

Measuring the Impact

Before the architecture refactoring:

MetricMonolith EraHook Architecture
AI-generated code acceptance rate~30%~85%
Time to onboard new developer2–3 weeks2–3 days
Average code review time per function25 min8 min
Merge conflicts per sprint8–120–2
Lines of code per business function200–50040–120

What Other Teams Can Learn

You don't need to use Logic Bee's exact architecture to make your codebase AI-ready. But these principles apply universally:

Principle 1: Predictable File Locations

If your AI has to guess where a file goes, it will guess wrong 30% of the time. A convention that maps names to paths eliminates this entirely.

Principle 2: Structured Metadata Over Comments

Comments are for humans. Decorators (or annotations, or frontmatter) are for machines AND humans. Use structured metadata for anything the AI needs to discover.

Principle 3: One Unit of Logic Per File

The smaller the blast radius of a change, the safer AI-generated code becomes. A wrong line in a 40-line file is easy to catch. A wrong line in a 400-line file is not.

Principle 4: Rigid Structural Templates

The more of your code that's identical across instances, the less the AI can get wrong. Boilerplate isn't the enemy — inconsistent boilerplate is.

Principle 5: Encode Conventions, Don't Assume Them

If a convention lives only in your head, the AI doesn't know it. If it lives in a skill file, the AI follows it automatically.

The Takeaway

AI-ready architecture isn't a separate initiative. It's good architecture: modular, predictable, self-describing, and convention-driven. The same decisions that make your codebase maintainable for a team of ten developers make it navigable for AI agents.

Design for the junior developer who just joined your team. The AI is that developer — permanently.

Skills as a Contract Between AI and Developer

· 4 min read
Gabriel Paunescu
Founder CTO Neologic

Skills aren't documentation. They're executable contracts — structured knowledge files that tell the AI exactly how your codebase works. Invest two hours writing a skill file, save twenty hours of correcting AI output.

The Premise

Most teams treat AI assistants like search engines: ask a question, get an answer, fix what's wrong. But Logic Bee takes a different approach. Instead of hoping the AI figures out how the code works, we tell it — through .agents/skills/ files that serve as machine-readable contracts between the developer and the AI.

The Story

Before skill files, every AI prompt required extensive context: "By the way, we use naoUtils.mathChain() for math, and naoDateTime() for dates, and errors should use naoFormatErrorById(), and the first thing in the try block should be eventOptions..."

One developer spent 15 minutes adding context to every prompt. Then they extracted it into a skill file — once. Now every AI interaction in the codebase automatically follows those conventions without any prompt engineering.

The return on investment was immediate: fewer review cycles, fewer rejected PRs, and dramatically fewer convention violations in AI-generated code.

What a Skill File Looks Like

# SKILL.md — hook-code-style

---
name: hook-code-style
description: Coding rules, naming patterns, and structural conventions for Logic Bee hooks
---

## Hard Rules (violations = merge blockers)

1. `ok` and `data` must be assigned before `returnEventResult`
2. Every `.flowQuery()` must include `.user(bob.flowUser)`
3. Every write operation must pass `bob.dbSession()`
...

## Soft Conventions (violations = code review comments)

1. `eventOptions` is the first declaration in the try block
2. Use arrow comments: `// -->Get:`, `// -->Set:`
3. Use `naoUtils.mathChain()` for all arithmetic
...

The skill is just a markdown file. But it transforms AI behavior from "best guess" to "informed generation."

What Makes a Good Skill

1. Be Prescriptive, Not Descriptive

❌ "We usually try to use mathChain for calculations"
✅ "ALWAYS use naoUtils.mathChain() for arithmetic. Raw +, -, *, / operators
on financial values are a hard rule violation."

2. Include Examples

Every rule should have a ✅ correct and ❌ incorrect code example. AI learns better from contrast.

3. Separate Hard and Soft Rules

The distinction matters. Hard rules should block generation. Soft rules should trigger warnings.

4. Keep It Focused

One skill per concern. hook-code-style covers coding patterns. flow-query covers database access. Don't mix them.

5. Document the Edge Cases

The 80% cases are obvious. Skills earn their ROI on the 20% that trips up AI:

"When a hook calls bob.runAction(), ALWAYS check the .ok property of the
result before continuing. AI tends to assume sub-requests always succeed."

The Skill Ecosystem

Logic Bee maintains a curated set of skills:

SkillContract
creating-hooksFile structure, decorator metadata, scaffolding CLI
bob-request-apiBobRequest accessors and lifecycle
flow-queryDatabase operations and tenant scoping
hook-code-styleNaming, formatting, structural rules
hook-validation-rulesHard rules and soft conventions
event-routingHow events dispatch to hooks
connectorsExternal API integration patterns
interfacesType definitions and data factories

Each skill is a contract: "If you follow these rules, the generated code will be correct."

Measuring ROI

Before and after skill files:

MetricBefore SkillsAfter Skills
AI-generated hooks needing revision70%15%
Convention violations per hook3.2 avg0.4 avg
Time from prompt to merge-ready25 min8 min
Developer context in prompts5–10 lines1 line (skill reference)

Writing Your First Skill

Start here:

  1. Pick your biggest pain point — what does the AI consistently get wrong?
  2. Write the rule — prescriptive, with examples
  3. Save it to .agents/skills/your-skill-name/SKILL.md
  4. Test it — prompt the AI to use the skill and check the output
  5. Iterate — add rules as you find new patterns the AI misses

The Takeaway

Skills are the highest-leverage investment you can make in AI-assisted development. They turn tribal knowledge into machine-readable contracts. The developer's job isn't to correct AI output — it's to define the rules that make correction unnecessary.

Write the contract once. Get correct code forever.

Debugging AI-Generated Code in an Event-Driven System

· 4 min read
Gabriel Paunescu
Founder CTO Neologic

The hook runs. It returns ok: true. The data looks right. But three hooks later in the pipeline, something breaks — and the stack trace points nowhere useful. Welcome to debugging in an event-driven system.

The Premise

Debugging AI-generated hooks is different from debugging hand-written code. The code looks correct — it follows every convention, passes validation, and compiles cleanly. But AI optimizes for pattern matching, not for understanding the execution context. When a bug hides in the space between hooks, traditional debugging falls apart.

The Story

A developer asks the AI to generate a hook for processing refunds. The hook queries the original invoice, calculates the refund amount, creates a credit memo, and updates the invoice status. The AI generates clean code. Tests pass. But in production, customers report that their invoice status shows "refunded" even when the credit memo creation fails.

The root cause? The AI wrote the status update before the credit memo creation — and without a shared database session, the two operations weren't atomic.

The Debugging Playbook

Step 1: Trace the Event Route

Every request in Logic Bee flows through: HTTP → Auth → FlowUser → Event Engine → Hook(s) → Response. When something goes wrong, first verify that the right hook is even being called:

// Add temporary logging at the top of the try block
console.log(`[DEBUG] ${new Date().toISOString()} - Hook entered`, {
hookPath: 'finance-bills/process-refund',
docId: bob.dataPayload?.docId,
userId: bob.flowUser?.getUserInfo()?.id
})

If you don't see this log, the event routing is wrong — check the @LogicHook decorator's path property.

Step 2: Verify the BobRequest Lifecycle

The bob object carries context through the entire execution. AI-generated code sometimes breaks the lifecycle by:

  • Modifying bob.dataPayload directly instead of using bob.replaceDataPayload()
  • Not passing bob.dbSession() to write operations, breaking transaction boundaries
  • Calling bob.executeRequestOrThrow() without error checking

Check the bob state at each step:

// -->Debug: log bob state before critical operations
console.log('[DEBUG] dataPayload:', JSON.stringify(bob.dataPayload, null, 2))
console.log('[DEBUG] dbSession exists:', !!bob.dbSession())

Step 3: Check Operation Order

AI generates operations in the order they appear in the prompt, which may not be the correct execution order. In the refund story, the fix was:

// ❌ AI-generated order (status before credit memo)
await updateInvoiceStatus(bob, 'refunded')
await createCreditMemo(bob, refundData)

// ✅ Correct order (credit memo first, then status)
const creditMemo = await createCreditMemo(bob, refundData)
if (creditMemo) {
await updateInvoiceStatus(bob, 'refunded')
}

Step 4: Verify Transaction Boundaries

When a hook performs multiple writes, all should share the same database session:

// ❌ AI sometimes creates independent write operations
await collection1.docs.flowQuery()...updateOne({ status: 'refunded' })
await collection2.docs.flowQuery()...insertOne(creditMemoDoc)

// ✅ Both must use bob.dbSession()
await collection1.docs.flowQuery()...updateOne({ status: 'refunded' }, bob.dbSession())
await collection2.docs.flowQuery()...insertOne(creditMemoDoc, bob.dbSession())

Step 5: Check Sub-Request Error Propagation

When hooks call other hooks via bob.executeRequestOrThrow() or bob.runAction(), AI sometimes ignores the returned error:

// ❌ AI ignores sub-request failure
const result = await bob.runAction('inventory.adjust-stock', { data: adjustmentData })
// continues execution even if result.ok === false

// ✅ Check the result
const result = await bob.runAction('inventory.adjust-stock', { data: adjustmentData })
if (!result.ok) {
throw result.error || naoFormatErrorById('bad_request', {
reason: 'Stock adjustment failed during refund processing'
})
}

Common AI-Generated Bug Patterns

PatternSymptomRoot Cause
Silent data corruptionDownstream hooks get wrong dataDirect bob.dataPayload mutation
Partial writesSome documents updated, others notMissing bob.dbSession() on some writes
Wrong hook calledAction does nothing or wrong thingDecorator path doesn't match expected route
Ignored sub-request errorsHappy path always succeedsMissing .ok check on runAction results
Race conditionsIntermittent failures under loadawait missing on async calls

The Takeaway

When debugging AI-generated hooks in a pipeline:

  1. Start at the route — is the right hook being called?
  2. Check the bob lifecycle — is the request context intact?
  3. Verify operation order — does the sequence match the business requirement?
  4. Audit every write — does each one use bob.dbSession()?
  5. Test sub-requests — are errors from child hooks handled?

The AI writes code that looks right. Your job is to verify it runs right — in context, in sequence, and under failure.

Prompt Engineering for ERP Logic: How to Talk to Your AI Agent

· 4 min read
Gabriel Paunescu
Founder CTO Neologic

The difference between a hook that needs 20 minutes of fixing and one that's merge-ready comes down to how you write the prompt. Garbage in, garbage out — but structured prompts unlock structured code.

The Premise

Logic Bee's AI agent has skills — structured knowledge files about the codebase's conventions, patterns, and tools. But skills are only activated when the AI recognizes them as relevant. A vague prompt activates vague knowledge. A precise prompt activates exactly the right skill at the right depth.

The Story

Two developers need the same hook: a function in the inventory-management library that adjusts stock levels after a sales order is confirmed. Here are their prompts:

The Vague Prompt

"Create a hook that updates inventory when an order is placed."

The AI generates a functional but generic hook. It uses a basic query pattern, doesn't reference the correct collection names, and invents a field structure that doesn't match the actual schema.

The Precise Prompt

"Create a new hook in inventory-management called adjust-stock-on-order-confirm. When a sales order status changes to 'confirmed', decrement the stock quantity for each line item. Use flowQuery to look up items by SKU in the inventory/items collection. Throw a bad_request error if any item has insufficient stock. Use the creating-hooks, flow-query, and hook-code-style skills."

The AI generates code that follows every convention, queries the right collections, handles edge cases, and validates inputs.

The Anatomy of an Effective Prompt

1. Name the Library and Method

Always specify where the hook lives. The AI uses this to set the file path, decorator metadata, and naming conventions.

❌ "Create a hook that..."
✅ "Create a new hook in finance-bills called calculate-late-fees..."

2. Describe the Trigger

ERP logic doesn't exist in isolation. Tell the AI when this logic runs.

❌ "Update inventory"
✅ "When a sales order status changes to 'confirmed'"

3. Specify Collections and Fields

The AI will guess field names if you don't provide them, and it will guess wrong.

❌ "Look up the product"
✅ "Use flowQuery to look up items by SKU in the inventory/items collection"

4. Define Error Conditions

Guard clauses and error handling are where AI-generated code is weakest. Explicitly state what should fail and how.

❌ "Handle errors"
✅ "Throw a bad_request error if any item has insufficient stock"

5. Reference Skills by Name

This is the multiplier. Skill references tell the AI exactly which knowledge to load.

❌ (no skill reference)
✅ "Use the creating-hooks, flow-query, and hook-code-style skills"

Prompt Template

Here's a copy-paste template for creating hooks:

Create a new hook in [library-slug] called [method-slug].

When [trigger condition], [primary action].
Use flowQuery to [query description] in the [collection-path] collection.
[Additional business rules].
Throw a [error-type] error if [failure condition].

Use the creating-hooks, flow-query, and hook-code-style skills.

Example using the template:

Create a new hook in shipping-management called calculate-shipping-rates.

When a sales order is ready for fulfillment, calculate shipping rates
for all available carriers. Use flowQuery to look up the order's line
items in the sales/orders collection and the customer's shipping address
in the contacts/addresses collection. Apply weight-based rate tiers
from the shipping/rate-tables collection. Throw a bad_request error if
the shipping address is missing or if total weight exceeds carrier limits.

Use the creating-hooks, flow-query, and hook-code-style skills.

Advanced Techniques

Ask for a Pattern Search First

Before generating new code, ask the AI to find similar existing hooks:

"Search for hooks that match the pattern 'calculate' in the finance-bills library."

This gives the AI a concrete reference implementation, producing much better results than generating from skills alone.

Chain Prompts for Complex Hooks

For hooks with multiple steps, break the work into sequential prompts:

  1. "Scaffold the hook structure for..."
  2. "Now implement the query logic using..."
  3. "Add validation for..."

Specify What NOT to Do

Negative constraints are surprisingly effective:

"Do not fetch all documents — use pagination. Do not calculate totals in JavaScript — use a database aggregation pipeline."

The Takeaway

Effective prompts for ERP logic follow a formula: name the location, describe the trigger, specify the data, define the errors, and reference the skills. The five minutes you spend writing a precise prompt save thirty minutes of fixing vague output.

Your prompt is your spec. Write it like one.

AI-Scaffolded Hooks: From Prompt to Production in 5 Minutes

· 3 min read
Gabriel Paunescu
Founder CTO Neologic

What if creating a new business logic hook took 5 minutes instead of 45? With AI-assisted scaffolding in Logic Bee, it can — but only if you know what to verify before hitting merge.

The Premise

Every Logic Bee hook follows the same anatomy: a @LogicHook decorator, a static execute() method, the Bob Wrapper pattern, and a returnEventResult call. That's a lot of boilerplate that's identical across hundreds of hooks — and boilerplate is exactly what AI excels at.

But scaffolding is only half the story. The other half is knowing what the AI cannot know: your business rules, your tenant boundaries, and the edge cases that live in your head.

The Story

A developer needs a new hook in the finance-bills library to calculate late fees on overdue invoices. Instead of copy-pasting from an existing hook, they open their AI agent and type:

"Create a new hook in finance-bills that calculates late fees on overdue invoices. Skip bills with zero balance. Use the creating-hooks and flow-query skills."

In under a minute, the AI:

  1. Runs the CLInpx tsx scripts/logic-bee-create-new-hook.ts scaffolds the folder, .hook.ts, hook.yml, and context.yaml
  2. Searches for patterns — finds calculate-bill as a reference implementation
  3. Writes the logic — generates a complete hook with FlowQuery chains, naoDateTime() comparisons, and naoUtils.mathChain() for fee calculations
  4. Self-validates — checks all 10 hard rules and 12 soft conventions

The developer has working code. But is it production-ready?

What the AI Gets Right

The generated hook follows every structural convention perfectly:

  • File path: hooks/finance-bills/calculate-late-fees/calculate-late-fees.finance-bills.hook.ts
  • Decorator metadata: name, path, library, method — all correctly derived
  • Bob Wrapper: let ok = true, error: any = null, datatry/catchreturnEventResult
  • Arrow comments: // -->Get:, // -->Set:, // -->Iterate:
  • Error handling: naoFormatErrorById('bad_request', { reason: '...' })

This is the 80% that would have taken a human 30 minutes to type.

What You Need to Verify

1. Tenant Scoping

Every FlowQuery chain must pass bob.flowUser. The AI almost always includes it, but a missing .user(bob.flowUser) means cross-tenant data leakage.

// ✅ AI usually generates this correctly
const bills = await fc.docs.flowQuery()
.user(bob.flowUser) // ← verify this exists on EVERY query
.flowOptions(eventOptions.billNaoQueryOptions)
.query({ 'data.status': 'posted' })
.getMany(undefined, 'FinanceInterface.Bill')

2. Business Logic Accuracy

The AI calculated late fees as a flat percentage. Your business rule says it should be tiered: 1.5% for 1–30 days, 3% for 31–60 days, 5% for 60+. The AI doesn't know this unless you told it.

3. Transaction Session Usage

For hooks that update multiple documents, verify bob.dbSession() is passed to all write operations. The AI may omit it on some update calls, breaking atomicity.

4. Edge Cases

The prompt said "skip bills with zero balance," and the AI added a guard clause. But what about negative balances (credits)? What about bills in draft status?

The Takeaway

AI scaffolding eliminates the mechanical overhead of creating hooks. Here's your pre-merge checklist:

  • .user(bob.flowUser) on every FlowQuery chain
  • bob.dbSession() on every write operation
  • Business logic matches actual requirements (not AI assumptions)
  • Edge cases covered: nulls, zero values, unexpected statuses
  • eventOptions declared at the top of the try block

The rule of thumb: let the AI write the structure, but own the logic.