I ported a knowledge-format (OKF) library to zero-dependency .NET — here’s what I learned

If you can cat a file, you can read the knowledge base. If you can git clone a repo, you can ship it. No vector database to stand up, no proprietary export format, no vendor lock-in — just a directory of markdown files with YAML frontmatter that a human can open in any editor and an agent can read with ReadFile. That’s the whole pitch, and it’s the reason I spent the last few weeks porting a Rust library to C# to get it onto .NET.

The format behind that pitch is Google’s Open Knowledge Format (OKF) v0.1, and the library is OKF4net (docs & project site) — a zero-dependency .NET (C#, net10.0) implementation, plus an optional layer for wiring OKF bundles straight into agents built on the Microsoft Agent Framework. This post is the launch story: what OKF actually is, why I ported it instead of writing a wrapper, and what « zero dependency » really costs and buys you.

What OKF is

OKF defines a bundle: a directory tree of UTF-8 markdown files, where each file is a concept — a YAML frontmatter block followed by a markdown body. Concepts cross-link each other with ordinary markdown links, index.md files give you progressive-disclosure directory listings, and log.md files record date-grouped change history. The only hard conformance requirement is a non-empty type field on every concept; everything else — unknown types, unknown keys, broken links — has to be tolerated by a conformant consumer. It’s deliberately boring as a format, which is the point: the format is context here, not the pitch. The pitch is what you get to do with plain files — diff them, review them in a PR, grep them, back them up with nothing but git.

The port story

This repository used to ship a Rust implementation of OKF. I removed it at commit d20343c — but only after proving, file by file and command by command, that the C# port produced byte-identical output. tests/fixtures/golden/ holds five golden captures taken directly from the Rust binary’s stdout — validate, info, graph --dot, fmt, and index — against a shared example bundle, and the C# CLI is diffed byte-for-byte against every one of them in CI. As of today the full suite passes end-to-end, including five byte-exact golden CLI comparisons against the original captures.

I’ll say the quiet part out loud: this port was AI-assisted, done largely with Claude Code driving the migration file by file, spec section by spec section, with the golden fixtures as the ground truth it had to match exactly. I think that’s worth stating plainly rather than glossing over — a byte-exact port across languages is a fairly mechanical, well-specified translation task with an unambiguous pass/fail signal (does the output match the captured bytes, yes or no), which is exactly the kind of task where an AI pair-programmer earns its keep and where you can trust the result because you can verify it byte-for-byte rather than having to take anyone’s word for it. The interesting design decisions — the YAML subset, the permissive-loading philosophy, the two-tier validation split — came from following the spec and the Python reference implementation; the AI assistance was in the grinding, get-every-byte-right execution, not the architecture.

Show, don’t tell

Here’s the library, loading a bundle and running a conformance check:

using OKF4net;

var bundle = Bundle.Load("./my_bundle");
Console.WriteLine($"{bundle.Count} concepts");

// Conformance check (§9).
var report = BundleValidator.Validate(bundle);
if (report.IsConformant)
{
    Console.WriteLine($"conformant with OKF v{OkfSpec.Version}");
}

// Traverse the cross-link graph.
var id = ConceptId.Parse("tables/orders");
foreach (var link in bundle.LinksFrom(id))
{
    Console.WriteLine($"{id} -> {link.Target} (exists: {link.Exists})");
}

Bundle.Load never aborts on a malformed concept file — it collects parse failures into bundle.ParseErrors and keeps walking the tree, because a knowledge base that one bad file can take down entirely is a bad knowledge base.

And here’s the CLI, which is the same tool the Rust binary used to be, invocation-for-invocation:

okf validate ./bundles/ga4
okf graph ./bundles/ga4 --dot | dot -Tsvg > graph.svg

okf validate exits non-zero on a non-conformant bundle, so it drops straight into a CI step. The CLI ships as a self-contained, Native AOT single-file binary — no .NET runtime install required on the machine that runs it.

The agents angle

The reason I care about this format enough to port a whole library for it is OKF4net.Agents, which turns an OKF bundle into tools and context for the Microsoft Agent Framework. OkfBundleTools wraps one bundle root and exposes nine function tools — read, browse, graph, search, write, append-log, regenerate-indexes, validate, changes-since — that an AIAgent can call directly:

var tools = new OkfBundleTools("./my_bundle");
AIAgent agent = chatClient.AsAIAgent(tools: tools.GetTools());
var response = await agent.RunAsync("Search the bundle for concepts about refunds.");

Layer OkfContextProvider onto the same tools instance and, opted in explicitly, an agent’s exchanges get captured as long-term memory — one markdown concept per UTC day, written through the same validated, lock-protected write path the tools use, plus a matching log.md entry. That’s the part I think is genuinely different from the usual answer to « give my agent memory »: instead of an opaque vector store you can’t audit, memory is a markdown file in a git-tracked directory. You can open it, diff it across commits, redact a line, or point a second agent at the exact same directory with no export step. It’s not a fit for every use case — the README is upfront that v1 memory is bundle-global and unscoped, so it’s opt-in and meant for a shared, non-sensitive bundle rather than a multi-tenant deployment — but for a single team’s shared knowledge base, « memory you can git blame » is a real capability, not a slogan.

Design choices

The whole library — OKF4net and OKF4net.Cli — has zero third-party runtime dependencies: no YAML library, no CLI-parsing package, nothing. It has its own documented YAML subset parser (frontmatter is scalars, lists, and shallow maps — no anchors, no tags, no multi-document files, and it says so with a clear error if you hand it those), its own markdown link scanner, and its own argument parsing, all on top of the .NET base class library. That constraint is what makes the CLI publishable as a single-file Native AOT binary with no runtime to install, and it’s what keeps the barrier to contributing low — there’s no framework to learn before you can read the code. OKF4net.Agents is the one exception, since talking to Microsoft.Agents.AI requires depending on it; everything else stays dependency-free by design, enforced project by project. The project also ships OKF4net.Catalog, a local multi-bundle catalog with search-by-source resolution, and OKF4net.Mcp, an MCP server that plugs a bundle straight into Claude Desktop or Claude Code — so agents and tools have a ready path to discover and query bundles without writing that plumbing themselves.

Come contribute

OKF4net is young and I’d rather it stay welcoming than gate-kept. You don’t need any prior OKF knowledge to help — the good first issue label names the files to touch and the test that should go green when you’re done, ROADMAP.md lays out where the project is headed, and Discussions is the place to ask a question before you write any code. The project is licensed LGPL-3.0-or-later, and the bar to your first PR is exactly three commands: dotnet build, dotnet test, dotnet format. If any part of « knowledge bundles you can cat and agents that remember things in files you can read » sounds useful to you, I’d love the help — and the feedback.

From Annoying Intern to Senior Sidekick: A Developer’s Guide to Mastering AI

Let’s be honest. We’ve all been there. You paste a chunk of code into an AI chat window, type « fix this, » and hold your breath, hoping for magic. What you get back is a syntactically correct, beautifully useless piece of nonsense that completely misses the point. You sigh, close the tab, and go back to cursing at your screen and console.log()-ing your way to a solution.

The initial « wow » factor of AI in software development has quickly been replaced by a more pragmatic, and sometimes frustrating, reality. These Large Language Models (LLMs) aren’t the magical oracles we were promised. They won’t steal our jobs tomorrow, but they are changing the very nature of our work. The difference between a developer who struggles with AI and one who thrives with it comes down to a simple, fundamental shift in mindset.

Stop treating your AI like a search engine or a magic 8-ball. Start treating it like a hyper-enthusiastic, infinitely patient, but slightly amnesiac junior developer.

Once you make that switch, everything changes.


The « Vague-Posting » Fallacy: Why Your Prompts Fail

You wouldn’t walk up to a new team member, vaguely gesture at a monitor, and say, « Code something. » You’d get a blank stare, and rightfully so. Yet, this is precisely how most developers interact with AI.

A bad prompt is the developer equivalent of vague-posting on social media. It lacks context, intent, and constraints.

  • Bad Prompt: Write a Python script for an API.
  • AI’s Inner Monologue: An API for what? Using which framework? Flask? FastAPI? What should the endpoints be? What data format? Does this person even know what they want?! I’ll just give them a generic Flask « Hello, World! » and hope they go away.

To get professional-grade output, you need to provide a professional-grade brief.

The Anatomy of a Killer Prompt: Giving Your Junior AI a Proper Spec

Think of your prompt as a ticket in Jira or a project brief. It needs to be clear, concise, and contain all the necessary information for your « junior dev » to succeed. Here’s your new checklist.

1. Assign a Persona: « You Are a… »
This is the most underrated trick in the book. By giving the AI a role, you anchor its knowledge base and response style. It’s the difference between asking a random person for directions and asking a seasoned taxi driver. Use instructions files for that, even generate instructions based on your codebase (GEMINI.md, AGENT.md, copilot-instructions.md, .cursorrules, etc.).

Example: "You are a senior backend developer with 15 years of experience in .NET Core and a specialist in postgres optimization."

2. Provide Rich Context: The Lay of the Land
Your intern can’t work in a vacuum. They need the full picture. This is the most crucial part. Don’t be lazy here (it will be time more consuming if you are). Provide:

  • Relevant Code: The specific function, class, or component you’re working on.
  • File Structure: If relevant, explain the project’s layout.
  • Dependencies & Versions: (Using .NET Core 9.x and EF Core 9.x)
  • The Goal: What business problem are you trying to solve? Why does this code need to exist?

3. Define the Objective & Constraints: The « What » and « What Not »
Be explicit about the task and, just as importantly, the boundaries.

  • The Task: "Refactor this function to improve its readability and performance."
  • The Constraints: "Do not add any new external libraries. The function must remain backward-compatible with the existing API signature. Ensure you add type hints and a clear docstring explaining the logic."

4. Show, Don’t Just Tell: The Power of Few-Shot Examples
If you want the output in a specific format, give it an example! This is called « few-shot prompting » and it’s incredibly effective.

Example: "I want you to generate unit tests. Here's an example of a test for a similar function: [Paste example test code]. Now, generate three new tests for the following function: [Paste new function code]."

5. Demand a Specific Output Format: The Deliverable
Don’t let the AI just dump a wall of text. Tell it exactly how you want the information presented.

Example: "Please provide your answer in a Markdown format. First, provide the refactored code in a .NET code block. Second, create a bulleted list explaining the key changes you made and why. Finally, provide a new set of unit tests in a separate code block."


The AI-Powered Workflow: Moving Beyond Simple Code Generation

With this robust prompting strategy, you can now integrate AI across your entire development lifecycle. It becomes less of a novelty and more of a force multiplier.

For Debugging:

  • Old Way: "My code is broken, here it is."
  • New Way: "You are an expert Typescript debugger. I'm getting a 'KeyError' on line 42 of this script. Here is the full function, the stack trace, and a sample of the JSON object that is causing the error. Explain the root cause and suggest two ways to fix it, one being a simple hotfix and the other being a more robust, long-term solution."

For Refactoring and Code Reviews:

  • Old Way: "Make this better."
  • New Way: "Act as a senior software architect conducting a code review. Analyze this TypeScript function for potential performance bottlenecks, anti-patterns, and opportunities to use more modern ES6+ features. Provide your feedback in a list, referencing line numbers and suggesting specific code improvements."

For Documentation and Onboarding:

  • Old Way: "Write docs for this."
  • New Way: "Generate a README.md file for this Go project. The project is a command-line tool that does [X]. Include sections for: 'What it is', 'Installation' (assuming Go 1.19+ is installed), 'Usage' with three clear command-line examples, and a 'Configuration' section explaining theconfig.yamlfile."

For Learning and Exploration:

  • Old Way: "Explain Rust's borrow checker."
  • New Way: "I'm an experienced C++ developer trying to understand Rust's borrow checker. Explain it to me using analogies related to C++ memory management, like smart pointers (unique_ptr, shared_ptr) and RAII. Provide a simple code example in both C++ and Rust to illustrate the concept of ownership."

The Human in the Loop: You’re Still the Pilot

Here’s the crucial takeaway: AI is a phenomenal co-pilot. It can handle navigation, check systems, and manage communications, freeing you up to focus on the hard stuff—like actually flying the plane.

Your value is no longer in your ability to write boilerplate code or remember the exact syntax for a LEFT JOIN. Your value is in:

  • Architectural Vision: Designing complex, scalable, and maintainable systems.
  • Critical Thinking: Knowing when a piece of AI-generated code is brilliant and when it’s dangerously naive.
  • Domain Expertise: Understanding the business logic and user needs that the code is meant to serve.
  • Prompt Engineering: The new meta-skill of effectively directing your AI partner.

The developers who will be left behind are the ones who either reject these tools entirely or use them naively. The ones who will thrive are those who master them, transforming their AI from an annoying intern into a trusted, senior-level sidekick.

So, the next time you open that chat window, take a deep breath. You’re not talking to a machine; you’re briefing your new junior. Give them the respect of a clear, detailed task, and you’ll be amazed at what they can do for you.

How to activate Bing Chat Enterprise

Here we are, Bing Chat Enterprise is out ! Have a look at the official product page : Your AI-Powered Chat for Work | Bing Chat Enterprise (microsoft.com). With Edge for Business already available, Edge is placing itself as personal and professional place to browse and use Internet service.

  1. Connect to this link to accept Bing Chat Enterprise Supplemental terms : https://www.bing.com/business/bceadmin
  2. Check the box to accept terms and click on Activate in Bing chat Enterprise zone :

In case of success you will have the following message :

If you are licensed for Microsoft 365 E3, E5, Business Standard, Business Premium, or A3 or A5 for faculty, it will comes at no additional costs for your company.

Next time, you and your collegues, will open Edge, you should see a Protected label in the upper right corner that indicates Bing Enterprise is enable and you can share data and conversations with Bing Chat securely and privately.