Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ It is built for useful, bounded work: data analysis, document generation, API wo
>
> **Platform note:** HyperAgent requires hardware virtualization: Linux with KVM, Azure Linux with MSHV, Windows with WHP, or WSL2 with KVM. It does not currently run on macOS [because of this Hyperlight issue](https://github.com/hyperlight-dev/hyperlight/issues/45).

## Quick Install

```bash
# Authenticate with GitHub (Copilot access required)
gh auth login

# Install and run
npm install -g @hyperlight-dev/hyperagent
hyperagent
```

Requires Node.js 22+ and hardware virtualization (Linux/KVM, Windows/WHP, Azure Linux/MSHV, or WSL2/KVM). For Docker, building from source, and full prerequisites, see [Install and Run](#install-and-run) below.

## Why HyperAgent?

Most agent CLIs are powerful because they can touch your machine directly: shell commands, file edits, network calls, local tools, credentials, and long-lived process state. That is useful, but it also means a bad instruction, hallucinated command, or prompt-injected webpage can become real host activity very quickly.
Expand Down Expand Up @@ -121,14 +134,14 @@ User prompt

The sandbox has no direct filesystem, network, shell, or process access. Capabilities are added deliberately:

| Capability | How it is exposed |
| ---------------- | ---------------------------------------------------------------- |
| Files | `fs-read` and `fs-write` plugins with path jails |
| HTTP | `fetch` plugin with domain allowlists and SSRF checks |
| Capability | How it is exposed |
| ---------------- | ------------------------------------------------------------------------- |
| Files | `fs-read` and `fs-write` plugins with path jails |
| HTTP | `fetch` plugin with domain allowlists and SSRF checks |
| Bash commands | `execute_bash` — sandboxed pure-JS interpreter (ls, grep, jq, curl, etc.) |
| Reusable code | `ha:*` system and user modules |
| External systems | MCP servers exposed as typed `host:mcp-*` modules |
| Bigger jobs | Profiles that raise limits; profile tools can enable plugin sets |
| Reusable code | `ha:*` system and user modules |
| External systems | MCP servers exposed as typed `host:mcp-*` modules |
| Bigger jobs | Profiles that raise limits; profile tools can enable plugin sets |

## Built-In Modules

Expand Down
68 changes: 57 additions & 11 deletions src/agent/approach-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,23 @@ import { loadPatterns } from "./pattern-loader.js";
import { loadModule, type ModuleHints } from "./module-store.js";

// ── MCP server name → CLI setup command mapping ──────────────────────
// Maps an MCP server name (as declared in skills) to the CLI flag that
// configures it. Used by formatGuidance() to show actionable hints.
// Maps an MCP server name (the key written into ~/.hyperagent/config.json
// under `mcpServers`) to the CLI flag that configures it. When a skill
// requires a server that is NOT yet configured, formatGuidance() uses
// this table to recommend the specific shortcut to the LLM (and through
// it, to the user). Servers absent from this table fall back to the
// generic "edit ~/.hyperagent/config.json" guidance — we deliberately
// don't suggest a `--mcp-setup-${name}` flag for unsupported names
// because that flag does NOT exist and would set the user up for failure.
//
// Keep in sync with the setup functions in src/agent/mcp/setup-commands.ts
// and the CLI cases in src/agent/cli-parser.ts.
const MCP_SETUP_COMMANDS: Record<string, string> = {
"fabric-rti-mcp": "--mcp-setup-fabric-rti",
everything: "--mcp-setup-everything",
github: "--mcp-setup-github",
filesystem: "--mcp-setup-filesystem",
workiq: "--mcp-setup-workiq",
};

// ── Types ────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -253,7 +266,42 @@ const GENERIC_GUIDANCE: MaterialisedGuidance = {
export function formatGuidance(guidance: MaterialisedGuidance): string {
const parts: string[] = ["--- TASK GUIDANCE ---"];

// Anti-patterns and rules go FIRST — the LLM is most likely to follow
// ── Unconfigured MCP servers go FIRST as a blocker ──────────────
// A missing prerequisite is the single most important thing the LLM
// needs to surface to the user. Buried under "Rules:" or "Modules:"
// it gets ignored — the model has been observed to skip the hint and
// hallucinate config.json snippets or non-existent CLI flags instead.
// Promoting this block to the top, with strong "TELL THE USER" wording,
// measurably improves the user-visible recommendation quality.
const missingMcp = guidance.mcpStatus.filter((s) => !s.configured);
if (missingMcp.length > 0) {
parts.push("🛑 MISSING PREREQUISITES — tell the user how to fix this:");
for (const s of missingMcp) {
const setupFlag = MCP_SETUP_COMMANDS[s.name];
if (setupFlag) {
// Explicitly supported — recommend the specific shortcut.
parts.push(
` ❌ MCP server "${s.name}" is required but not configured.`,
` SHORTCUT: have the user run \`hyperagent ${setupFlag}\` ` +
`(exits after writing config, then restart hyperagent).`,
);
} else {
// Not in the supported-shortcuts table — give honest generic
// guidance. DO NOT suggest a `--mcp-setup-${name}` flag here;
// that flag does not exist and the user will hit "unknown
// option" if you say it does.
parts.push(
` ❌ MCP server "${s.name}" is required but not configured.`,
` This server has no built-in setup shortcut. Tell the ` +
`user to add it to \`~/.hyperagent/config.json\` under ` +
`\`mcpServers\` (see https://modelcontextprotocol.io for ` +
`the entry shape), then restart hyperagent.`,
);
}
}
}

// Anti-patterns and rules — the LLM is most likely to follow
// instructions at the top of the context injection.
if (guidance.antiPatterns.length > 0) {
parts.push("⚠️ DO NOT:");
Expand All @@ -278,15 +326,13 @@ export function formatGuidance(guidance: MaterialisedGuidance): string {
`Plugins: ${guidance.plugins.join(", ")} — enable via manage_plugin or apply_profile`,
);
}
if (guidance.mcpStatus.length > 0) {
// MCP server status block — only shows CONFIGURED servers here.
// Unconfigured ones are surfaced above as missing prerequisites.
const configuredMcp = guidance.mcpStatus.filter((s) => s.configured);
if (configuredMcp.length > 0) {
parts.push("MCP Servers:");
for (const s of guidance.mcpStatus) {
if (!s.configured) {
const setupFlag = MCP_SETUP_COMMANDS[s.name] ?? `--mcp-setup-${s.name}`;
parts.push(
` ❌ ${s.name} — not configured. Run: hyperagent ${setupFlag}`,
);
} else if (s.state === "connected") {
for (const s of configuredMcp) {
if (s.state === "connected") {
parts.push(
` ✅ ${s.name} — connected (${s.toolCount ?? 0} tools). Import from host:mcp-${s.name}`,
);
Expand Down
Loading
Loading