Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

techradar

License: MIT The method Essays

An interactive Tech Radar you can host anywhere, driven by one JSON file, with a validator that enforces the thing that actually makes a radar useful: evidence.

The viewer showing the bundled sample radar

Most radar tools help you draw a picture. The picture is the easy part. The hard part is stopping the radar from becoming a list of opinions — and that is a discipline problem, not a rendering problem. So this tool ships with the discipline built in:

  • Every blip carries evidence, split into stated (somebody told you) and observed (it is checked into a repository).
  • techradar validate -strict fails the build when a blip in the innermost ring lacks both kinds.
  • techradar diff compares two editions and fails when the radar contradicts what it says about itself — a blip that moved inward while its movement field says NO CHANGE is a lie a reader would never catch.
  • Every blip records what would move it inward, so the next edition has somewhere to start.
  • techradar mcp puts the whole thing where a coding agent can ask about it mid-task.

The method behind those rules is written up in docs/METHOD.md — read that if you want the reasoning rather than the tool. The practice it encodes is written up in From Signals to Blips: how a weekly sweep turns raw reports into scored candidates, and why the agent running that sweep is never allowed to edit the radar itself.

Quick start

go run . serve
# open http://localhost:8080

That serves the bundled sample radar. Then point it at your own:

go run . init my-radar     # scaffold web/ and data/ into my-radar/
cd my-radar
go run github.com/bfrackowiak/techradar@latest serve

Or grab a binary from Releases — the viewer and a starter radar are compiled in, so a single downloaded file is a working radar with nothing else to install:

./techradar serve

What you get

One file to edit data/radar.json is the entire radar. No database, no build step, no admin UI.
Zero runtime dependencies The viewer is one self-contained HTML file — no framework, no CDN, no bundler. The server is Go's standard library.
Hosts anywhere Any static host works. A GitHub Pages workflow is included.
A validator worth running Structural checks always; the evidence rules under --strict. Wire it into CI so a radar change is reviewed like code.
Nothing hard-coded Ring and quadrant names, counts, and colours are all data. Geometry is derived from them.

Commands

techradar serve     [-port N] [-dir PATH] [-host H]        Serve the viewer over HTTP
techradar validate  [-strict] [-quiet] [PATH]              Check one radar; non-zero exit on problems
techradar diff      [-format F] [-o FILE] OLD NEW          Compare two editions
techradar diff      [-git REV] [-fail-on-problems] [PATH]  …or compare against a git revision
techradar mcp       [-dir PATH]                            Answer agent queries over stdio
techradar init      [-force] [DIR]                         Scaffold a starter radar
techradar version                                          Print the build version

serve reads ./web and ./data when they exist and falls back to the copies built into the binary when they do not. It sets Cache-Control: no-store on everything, so editing data/radar.json and reloading the page is the whole edit loop. GET /healthz reports the same validation problems as the CLI, which is convenient to poll from an editor.

Checking a radar against itself

validate can only judge a snapshot. Every rule it enforces holds inside one file at one moment. But the part of the method that keeps a radar alive lives between editions — movement, exit conditions, promotion when a stated condition is met. The movement field is prose the author types, nothing stops it being wrong, and it is the field a reader trusts most.

techradar diff -git HEAD~1                 # what changed since the last commit
techradar diff old.json new.json           # or two files
Agentic Engineering Radar   edition 8 (2026-08-03) -> edition 9 (2026-08-10)

  0 added   2 ring moves   1 retired   1 revised

RING MOVES
  >  Hooks as Deterministic Enforcement  Trial -> Adopt  inward
  >  Log Search MCP                      Trial -> Adopt  inward

PROBLEMS (2)
  !  blip "Log Search MCP": moved Trial -> Adopt but movement says NO CHANGE
  !  blip "Wiki MCP": changed in this edition but editionUpdated is 0, not 9;
     the change will not be marked for readers

What it catches:

Contradiction Why it matters
Ring moved, movement says NO CHANGE The radar lies in the field read most carefully
MOVED IN claimed, ring went outward Direction is checked, not just the vocabulary
MOVED IN on a blip that did not move Last edition's value, carried forward — the commonest error
A blip claims NEW but was already there The badge fires for a blip nobody added
Content changed, editionUpdated not bumped A change no reader will find
A blip vanished Silent removal is how a radar rewrites its own history
More than five moves without an edition bump The project's own publication rule

A movement claim is scoped to the edition named in editionUpdated: a blip that says it last changed in edition 4 is describing edition 4, and this comparison has nothing to say about it. Without that scoping, every real finding drowns in years of correct bookkeeping.

It also reports blips sitting still — anything unchanged for three editions or more, with the exit condition it wrote for itself, so the next edition starts from a list instead of a blank page. The innermost ring is excluded: a settled recommendation not moving is the radar working, not a problem.

Four output shapes: -format text (default), markdown for a pull-request body or release note, html for a standalone changelog page, and json for other tools. -o FILE writes to disk.

In CI, -fail-on-problems turns all of this into a gate — see .github/workflows/ci.yml, which runs it on every pull request and posts the changelog to the job summary.

Connecting an agent

A ring is an instruction. Adopt means stop evaluating alternatives and use this — and that instruction only does any work if it reaches the moment a choice is made. Today it reaches a document somebody reads once a quarter.

techradar mcp -dir /path/to/radar

That speaks the Model Context Protocol over stdio, exposing four tools:

Tool Question it answers
radar_position What is our position on X, and what does that ring tell me to do?
radar_search What do we have on this topic, filtered by ring or quadrant?
radar_blip The full briefing, including every piece of evidence and its source
radar_summary What is this radar, and how is it distributed?

The radar is re-read on every call, so an agent sees your edits without a restart. Ambiguous lookups return the candidates rather than guessing — a silently wrong blip is a wrong recommendation delivered with confidence.

While serve is running, the viewer shows a Connect an agent panel with the client configuration ready to copy. On a static host there is no process to connect to, the endpoint is absent, and the button stays hidden.

Project layout

main.go              CLI dispatch and flag parsing only
internal/radar/      the document, parsing, and the validation rules
internal/diff/       edition comparison, self-contradiction checks, renderers
internal/mcp/        JSON-RPC 2.0 / MCP server over stdio
internal/web/        HTTP handlers for the viewer, data and agent panel
web/index.html       the viewer: one file, no framework, no build step
data/radar.json      the radar
schema/              JSON Schema for editor completion

The data format

{
  "title":     "Agentic Engineering Radar",
  "edition":   8,
  "date":      "2026-08-03",
  "author":    "Architecture Guild",

  // Both lists are free-form. Position determines geometry and colour;
  // the text is never interpreted. Rename them to suit your organisation.
  "quadrants": ["Techniques", "Tools", "Platforms & Integrations", "Context & Knowledge"],
  "rings":     ["Adopt", "Trial", "Assess", "Hold"],

  "ringColors":   ["#4a8c3d", "#1f6dbe", "#c97a1e", "#b8362f"],  // optional
  "ringMeanings": [ /* optional prose for the "What do the rings mean?" panel */ ],

  "blips": [
    {
      "name":       "Hooks as Deterministic Enforcement",
      "ring":       "Trial",          // must appear in "rings"
      "quadrant":   "Techniques",     // must appear in "quadrants"
      "confidence": "strong",         // strong | medium | weak

      "what":      "One sentence. What is this thing?",
      "reasoning": "Why this ring, in your own voice. This is the part people read.",
      "risks":     "What would move it inward one ring, or what to watch for.",

      "movement":     "NEW",          // NEW | MOVED IN | MOVED OUT | NO CHANGE
      "movementNote": "A new architectural primitive the radar lacked. Skills teach; hooks gate.",

      "editionAdded":   3,            // drives the NEW badge
      "editionUpdated": 3,            // drives the UPDATED badge

      "evidence": [
        { "kind": "stated",   "source": "sources/weekly-signals-w05.md", "who": "Staff Engineer, Platform/Infrastructure",
          "quote": "The brief is read once and then it is advisory. The hook is not advisory." },
        { "kind": "observed", "path": "platform-core/.agent/hooks/",
          "note": "Six hooks: branch naming, commit format, read-only guard, sensitive-file guard." }
      ]
    }
  ]
}

Unknown keys are a hard error. A misspelled reasonning would otherwise render as an empty section that nobody notices, so the parser rejects it instead.

What --strict enforces

Rule Why
Every blip has at least one evidence entry Cite or it did not happen.
what, reasoning, risks, movement are all present A blip without reasoning is a logo on a slide.
A blip in the innermost ring has both stated and observed evidence The strongest recommendation you make needs someone who says they do it and an artefact proving they do. Testimony alone is aspiration.
observed evidence has a path; stated evidence has a source Evidence you cannot follow back is not evidence.

Plain validate skips those and checks structure only: ring and quadrant names resolve, no duplicate blip names, editions are consistent, colours match the ring count.

Publishing

GitHub Pages. .github/workflows/pages.yml assembles the viewer and data into a static site and deploys it. Enable Pages with source GitHub Actions in repository settings and push. There is no build step — it copies two files.

Anywhere else. Serve web/index.html as the page and data/radar.json beside it at data/radar.json. That relative path is the only contract, which is why the same file works locally and on a static host.

Using it in CI

- uses: actions/setup-go@v5
  with: { go-version: '1.24' }
- run: go run github.com/bfrackowiak/techradar@latest validate -strict data/radar.json

A pull request that moves a blip inward without adding the evidence to justify it now fails, which is the point: the review conversation happens against a rule everyone agreed to in advance rather than against whoever feels strongly today.

Building

go build -o techradar .                             # current platform
GOOS=windows GOARCH=amd64 go build -o techradar.exe .
go test ./...

No dependencies beyond the standard library, so there is no module download step and nothing to audit.

The sample radar

data/radar.json ships with a 73-blip radar tracking one organisation's adoption of agentic AI in software delivery across eight editions — spec-driven development, sub-agent orchestration, MCP integrations, plugin marketplaces, and the governance problems that showed up once agents started writing production code.

It is there because a two-blip sample teaches you nothing about running a radar. This one exercises every mechanism at realistic scale: blips that moved inward on a met condition and outward on new evidence, NO CHANGE entries carrying an updated note, counter-signals recorded against the author's own argument, and Hold entries that each name a specific harm rather than a preference.

The organisation is fictional. The practices and failure modes are real industry ones, but the teams, roles, quotes, figures, file paths and incidents are all invented to demonstrate the format. Nothing in it describes a real company — in particular, it is not the radar described in From Signals to Blips; that one is not published, and no part of it appears here. Replace this sample with techradar init or by editing the file.

The thinking behind it

This tool is the executable part of a weekly essay series on software architecture and the organisations that produce it — bfrackowiak.pl (RSS). The rules the validator enforces were argued there first.

Essay Why it matters here
From Signals to Blips The method this tool encodes: cite or it didn't happen, the weekly sweep, and why the agent proposes candidates but never edits the radar.
Probabilistic Metrics Why confidence is a separate field from ring — signal strength is not validation status.
Data-Driven Theater Why evidence carries a kind and a source you can follow: a number without its preprocessing is a prop.
The Bottleneck Moved The finding behind the sample's delivery-bottleneck blip: agents optimised the cheap half of the pipeline.
Multi-Agent Is an Org Chart Where the sample's orchestration and role-collapse entries come from.
Nobody Owns the Sum Why a blip names an owner and an exit condition, or it drifts unowned like the sample's context-fabric entry.
Adoption Is the Deliverable Why the innermost ring is an instruction with a verb rather than a compliment.

Contributing

See CONTRIBUTING.md.

Licence

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages