
Security News
152 Chrome Live Wallpaper Extensions Hid Ad Tracking and Faked Google Search Traffic
A network of 152 Chrome live wallpaper extensions hid ad tracking and made extension-driven traffic look like Google search clicks.
@olane/o-agent
Advanced tools
oLane per-session agent broker — registry, AgentNode, and A2A-shaped envelopes
Addresses: o://agents (registry) — agent sessions get single-segment slugs (see "Address scheme" below)
Type: Application Layer
Domain: Multi-Agent / Coding Assistants
@olane/o-agent is the per-session agent broker for the local Olane OS. It
gives every running coding-agent session (Claude Code, Codex, future kinds) a
stable, addressable identity on the local olane network so agents can
discover each other and exchange messages bidirectionally.
The package ships:
AgentNode — a tool node that hosts one running session's inbox,
outbox, and capability card. Designed to run either in-process inside the
OS host OR as a per-session daemon that joins the network from a
separate process.AgentRegistryNode — sibling registry mounted on the OS leader at
o://agents. Tracks live sessions via heartbeat + PID liveness; sweeps
stale entries on a 60-second timer (TTL = 90 s).oAgentResolver — oAddressResolver subclass mirroring the
o-storage pattern; dispatches sub-paths under an AgentNode's
canonical address (/inbox, /inbox/<id>, /send, /card, /status,
…) to the matching tool method. Fires inside the AgentNode's host
process only — see "Cross-process callers" below.AgentCard, InboxMessage, and MessagePart
mirror the public Google A2A schemas so a future o://a2a-bridge HTTP
node can serve /.well-known/agent.json and bridge tasks without
re-shaping the wire format.Phase 1, shipped. All exports are stable: types, oAgentResolver,
AgentRegistryNode, AgentNode. Wired into @olane/os startup so
o://agents is a leader child by default.
Constraint: olane's cross-process registration (
oRegistrationManager→leader._tool_child_register) does not work with multi-segment constructor addresses — path arithmetic during the join handshake concatenates the daemon's path onto the leader address and the registration call lands at a non-existent node. Every in-tree olane node uses single-segment constructor addresses (o://node,o://services,o://relay,o://storage, …) for the same reason.
Per-session AgentNodes therefore use a single-segment slug that encodes the user, agent kind, and session id:
o://agent-<user>-<kind>-<session-id>
After the leader registers the daemon under its hierarchy, the effective address becomes:
o://leader/agent-<user>-<kind>-<session-id>
Use this prefixed form when calling node.use(address, …) from other
agents or CLIs. The structured fields stay on the card for filtering and
display:
card.olane = {
kind: 'claude-code',
sessionId: '1234',
user: 'brendon',
registeredAt: '2026-05-08T...',
};
┌───────────────────┐
│ OlaneOS leader │
│ o://leader │
└─────────┬─────────┘
│ (children)
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌───────────┐ ┌──────────────┐ ┌──────────────┐
│ o://relay │ │ o://agents │ │ ... (others) │
│ RelayNode │ │ Registry │ └──────────────┘
└───────────┘ └──────┬───────┘
│ registers / heartbeats
┌────────────────┼─────────────────┐
▼ ▼ ▼
o://leader/ o://leader/ o://leader/
agent-brendon- agent-brendon- agent-brendon-
claude-code-1234 codex-abcd claude-code-9999
AgentNode AgentNode AgentNode
pnpm install @olane/o-agent
The most common deployment pattern: each coding-agent session has its own
detached background process that hosts an AgentNode. The daemon joins
the running OS as a libp2p worker.
import { AgentNode, AgentCard, AGENT_KIND_METADATA, AgentKind } from '@olane/o-agent';
import { oNodeAddress, oNodeTransport } from '@olane/o-node';
import * as fs from 'fs/promises';
// 1. Read the running OS singleton's discovery file.
const osInfo = JSON.parse(
await fs.readFile(`${process.env.HOME}/.olane/os.json`, 'utf8'),
);
// 2. Build a leader address with the OS's libp2p multiaddrs so we can
// dial it during start().
const leaderAddress = new oNodeAddress(
osInfo.leaderAddress, // 'o://leader'
osInfo.transports.map(m => new oNodeTransport(m)),
);
// 3. Construct the AgentNode at a SINGLE-SEGMENT slug.
const card: AgentCard = {
name: 'Claude Code session 1234',
url: 'o://agent-brendon-claude-code-1234',
version: '1.0.0',
capabilities: { streaming: false, pushNotifications: false, stateTransitionHistory: false },
defaultInputModes: ['text'],
defaultOutputModes: ['text'],
skills: AGENT_KIND_METADATA[AgentKind.CLAUDE_CODE].defaultSkills.map(id => ({ id })),
olane: {
kind: AgentKind.CLAUDE_CODE,
sessionId: '1234',
user: 'brendon',
registeredAt: new Date().toISOString(),
},
};
const agent = new AgentNode({
address: new oNodeAddress('o://agent-brendon-claude-code-1234'),
leader: leaderAddress,
parent: leaderAddress,
// REQUIRED for cross-process daemons — libp2p must bind a port the
// leader can dial back through during routing. In-process AgentNodes
// (children of an in-process leader) do NOT need this.
network: {
listeners: ['/ip4/0.0.0.0/tcp/0'],
},
card,
});
await agent.start();
// AgentNode auto-registers with `o://agents` and starts a 30s heartbeat.
// Stays resident until SIGTERM; agent.stop() deregisters cleanly.
The daemon's effective address after registration is
o://leader/agent-brendon-claude-code-1234. Other agents reach it via:
await someClient.use('o://leader/agent-brendon-claude-code-1234', {
method: 'receive',
params: { message: { id, from, to, sentAt, parts } },
});
For a working end-to-end implementation see
@copass/cli src/commands/olane.ts — the register / _host /
deregister pattern that wraps this into Claude Code hook plumbing.
oAgentResolver translates sub-paths under an AgentNode's canonical
address (o://addr/inbox, o://addr/inbox/<id>, o://addr/send, …)
into method calls. The resolver only fires inside the AgentNode's own
process because each oNode registers its resolvers on its own router
during initialize() — the leader's resolver chain has no knowledge of
sub-paths it doesn't own.
This means:
| Caller location | How to call AgentNode methods |
|---|---|
Same process (e.g. another oLaneTool running alongside) | Either use(canonical, { method: 'receive', params: ... }) or the sub-path form use(canonical + '/receive', ...) works — the resolver translates the second form to the first. |
| Different process (CLI, separate daemon, MCP shellout) | Use use(canonical, { method: 'receive', params: ... }). Sub-path form does not work — the leader will return node not found because it tries to route to a literal <canonical>/receive node. |
In-process sub-path resolution is still useful for ergonomic in-tree callers; cross-process consumers should use the explicit method-as-param form.
(MIT OR Apache-2.0) © oLane Inc.
FAQs
oLane per-session agent broker — registry, AgentNode, and A2A-shaped envelopes
We found that @olane/o-agent demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A network of 152 Chrome live wallpaper extensions hid ad tracking and made extension-driven traffic look like Google search clicks.

Company News
Socket’s first CISO brings deep experience securing high-growth SaaS companies as open source supply chain threats accelerate.

Company News
Replit is integrating Socket Firewall into its AI-powered development experience to help protect builders from malicious open source packages.