Viper

Agents, thirty years early.

Viper is an agent programming language I designed and built in the 1990s for the ADEPT project — one of the first multi-agent systems research programmes — where it powered ICI's agent demonstrator. It was a complete environment: a language, a compiler, a byte-code virtual machine, a persistent distributed object space, an agent server, and an IDE — written in C++ for Windows NT.

ADEPT (Advanced Decision Environment for Process Tasks) ran under the DTI/EPSRC Intelligent Systems Integration Programme, led by BT Laboratories with ICI Engineering Technology, Loughborough University and Queen Mary & Westfield College. ICI's demonstrator managed a real engineering workflow — Relief & Blowdown, the process-safety design of pressure systems — with each design activity modelled as an autonomous, service-providing agent. The source survives.

In 2026 I had Claude audit the original C++ codebase — every opcode, every design memo. This page is what we found.

  • 210byte codes
  • 71keywords
  • 18shipped binaries
  • 1developer

1 · The Language

Agents and Guards

In Viper, Agent is a keyword. An agent is an object with its own message loop and communication channels; it registers the services it provides and requests the services it needs. The language has no pointers — the June 1996 design memo is titled, simply:

“Goodbye to Pointers. VIPER will not support pointers. The user will always have an instance of a variable to work with.”

Its most distinctive feature is the Guard — a declarative interceptor on assignment and function call. A guard validates in Pre Execute, performs (or declines) the operation in Execute, and propagates consequences in Post Execute. And when a value fails validation, a guard can assume a substitute — recorded in an assumptions table, with history, to be revisited:

  1. Agent Pump
  2. {
  3. Integer pressure | notGreaterThan10
  4. }
  5. Guard notGreaterThan10 (Integer value)
  6. {
  7. Pre Execute
  8. {
  9. expects (value <= 10 and value >= 0) then
  10. UpdateHistoryTable(Target)
  11. else expects (value > 10)
  12. {
  13. assume value = 10 // recorded, auditable, revisitable
  14. UpdateHistoryTable(Target)
  15. }
  16. exception
  17. {
  18. Error ("Value must be between 0 and 10")
  19. exit
  20. }
  21. }
  22. Execute
  23. {
  24. Target = value
  25. }
  26. Post Execute
  27. {
  28. UpdateClientServer (Target) // propagate across the network
  29. }
  30. }

Engineering design runs on provisional numbers; Viper made the assumptions themselves first-class — tracked, audited, revisitable. Thirty years on, AI agents hallucinating on unstated assumptions remains the field's central reliability problem. Viper had a keyword for it in 1996.

2 · The Compiler & the Machine

From Source to Byte Code

A two-pass compiler (symbols, then code) compiles agents into byte code for a custom virtual machine: 210 instructions, a virtual register file modelled on the i386, dual stacks, and a dispatch loop that calls each opcode handler through inline assembly. The unusual part is the output — the compiled program is itself an object graph, in the same representation as runtime data. Code, data and metadata are one structure, position-independent down to every internal reference.

Viper source vcc · symbols vcc · byte code object graph (.bin) Byte Code Machine Agents on the network

That one property — everything serializable, everything relocatable — is what made agents storable, transmittable and inspectable: the disassembler, the agent viewer and the network transport all just walk the same graph.

3 · The Runtime

A Distributed Object Space

Every machine ran a Common Object Space — a persistent, reference-counted object store with named objects, links between them, and transparent disk paging: an object faulted in from disk has its address patched into the calling byte code, so the next call is direct. Agents communicated over channels with three transports behind one interface — shared memory locally, named pipes, Winsock sockets remotely — and each object exported a channel map: a finite number of typed connection slots per field, with contention escalated to a broker that resolves it by protocol.

4 · Distribution

The Trader: Services, Discovery, SLAs

A per-machine server brokered everything: agents registered their services in a services table; requests that couldn't be satisfied locally fanned out across the network; results came back correlated by — the term in the 1996 source code — an SLA id. Service-level agreements between negotiating agents were ADEPT's research theme, and they are written into Viper's wire protocol. Agents could be serialized into an agent store and addressed in memory, on disk, or on the network — the groundwork for mobile agents, with design documents describing “travelling demons”: code that accompanies an object to a new machine and adapts its protocol to local conditions.

5 · The Tooling

Vibe — Yes, It Was Really Called Vibe

Viper shipped with its own IDE, and its name is written into the June 1996 white paper: Vibe, the Viper Integrated Build Environment. The binary on my disk is Vibe.exe; the settings file is vibe.ini. Twenty-nine years later the industry coined “vibe coding” for building software by telling an AI agent what you want. I'd like the record to show: the agents came with a Vibe first.

Vibe coding, 1996: open Vibe, wizard an agent from a dialog resource, hit compile, and your agent is on the network.

It earned the name. A tabbed editor, an applet wizard that scaffolded a working agent from a dialog resource, one-keystroke compilation, and a byte-code disassembler that rendered any compiled function straight from the object graph. UI work was declarative — On Message ID_FIRECALC FireDialog bound a window message to an agent function, and the compiler and runtime met in the middle. The pattern of language, runtime and IDE designed together as one product is the same instinct I followed again, two decades later, with Au.

6 · Thirty Years On

Viper in the Age of AI Agents

The 2024–26 agent stack is rebuilding this layer, mostly without knowing it existed. The mapping is uncomfortably precise:

  • The Trader — per-machine service registry with network fan-out → today's MCP registries and tool discovery.
  • SLA-correlated requests — typed, asynchronous service invocation → today's agent-to-agent protocols and function calling.
  • Guards — pre/post interception with protocols that travel with the data → today's guardrails, validators, and permission gates.
  • The Agent Store — serialized agents addressable in memory, file or network → today's agent marketplaces and durable execution.
  • assume — first-class, auditable assumptions → still unsolved. The best idea in the system is the one nobody has rebuilt yet.
  • Vibe — the IDE for building agents, 1996 → “vibe coding”, 2025. Sometimes the future just borrows the name.

What the 1990s lacked was the reasoning core. Guards and negotiation strategies could encode rules, but the agent vision needed judgment — and no logic engine ever delivered it. That missing component took thirty years to arrive, and it turned out to be a language model, not a planner. The audit's verdict belongs to the auditor:

“You built the agent operating system thirty years before the agent arrived to run on it.”
— Claude, after reading the source, 2026

Viper was the first language I built; Au was the second. Today at Nearfield.ai I'm building the third chapter: OS/A, an Operating System for Agency — the same secure agent orchestration problem I started on in 1994, with the missing piece, the reasoning engine, finally available.

OS/A is what happens when the agent finally arrives.

A footnote that closes a loop: ADEPT was led by Professor Nick Jennings — who, years later, was the external examiner of my PhD, Machine Acts. The man who ran the project Viper was built for went on to examine the thesis that followed it.

The full story is on the Experience page, or get in touch.