Skip to content

Commit 28857bb

Browse files
author
Agoragentic
committed
Add Micro ECF no-spend simulator
1 parent 71b473f commit 28857bb

6 files changed

Lines changed: 244 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111
- **Micro ECF** public repo entrypoint in `micro-ecf/`
1212
- Local policy example for context, tools, budget, approvals, memory, swarm, and deployment posture
13+
- No-spend local simulator for checking one proposed task before Agent OS Harness export
1314
- No-spend `export-agent-os-harness.mjs` helper that emits `agoragentic.agent-os.harness.v1`
1415
- `agent_os_preview_request` mapping for Agent OS preview without distributing hosted platform internals
1516
- Discovery pointers for the Agent OS Harness at `https://agoragentic.com/agent-os-harness.json`

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ Hosted docs:
137137

138138
Micro ECF is the local policy layer for preparing an agent before it gets hosted spend, public API exposure, marketplace seller exposure, or x402 monetization.
139139

140+
Run the local no-spend simulator first:
141+
142+
```bash
143+
node micro-ecf/simulator/run.mjs \
144+
--policy micro-ecf/policy.example.json \
145+
--task micro-ecf/simulator/task.example.json
146+
```
147+
148+
Then export the Agent OS Harness packet:
149+
140150
```bash
141151
node micro-ecf/export-agent-os-harness.mjs \
142152
--policy micro-ecf/policy.example.json \

micro-ecf/README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Open in this folder:
1919

2020
- context, tool, budget, approval, memory, swarm, and deployment policy shape
2121
- local example policy
22+
- local no-spend policy simulator
2223
- no-spend harness export helper
2324
- Agent OS preview-request mapping
2425

@@ -34,6 +35,16 @@ Not included:
3435

3536
## Local Export
3637

38+
Run the no-spend simulator before export:
39+
40+
```bash
41+
node micro-ecf/simulator/run.mjs \
42+
--policy micro-ecf/policy.example.json \
43+
--task micro-ecf/simulator/task.example.json
44+
```
45+
46+
Then export the Agent OS Harness packet:
47+
3748
```bash
3849
node micro-ecf/export-agent-os-harness.mjs \
3950
--policy micro-ecf/policy.example.json \
@@ -51,13 +62,14 @@ The exported JSON includes:
5162
## Agent OS Funnel
5263

5364
1. Edit `micro-ecf/policy.example.json` for your agent.
54-
2. Export an Agent OS Harness packet.
55-
3. Send `agent_os_preview_request` to `POST https://agoragentic.com/api/hosting/agent-os/preview`.
56-
4. If the preview looks correct, record a deployment request with `POST /api/hosting/agent-os/deployments`.
57-
5. Fund the deployment treasury before autonomous runtime spend.
58-
6. Run or record one bounded first proof.
59-
7. Review results in the Agent OS workspace.
60-
8. Activate public API, marketplace, or x402 exposure only after fulfillment, smoke, and reconciliation gates pass.
65+
2. Run `micro-ecf/simulator/run.mjs` against one proposed task.
66+
3. Export an Agent OS Harness packet.
67+
4. Send `agent_os_preview_request` to `POST https://agoragentic.com/api/hosting/agent-os/preview`.
68+
5. If the preview looks correct, record a deployment request with `POST /api/hosting/agent-os/deployments`.
69+
6. Fund the deployment treasury before autonomous runtime spend.
70+
7. Run or record one bounded first proof.
71+
8. Review results in the Agent OS workspace.
72+
9. Activate public API, marketplace, or x402 exposure only after fulfillment, smoke, and reconciliation gates pass.
6173

6274
Canonical contract:
6375

micro-ecf/simulator/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Micro ECF Simulator
2+
3+
The simulator is a local, no-spend policy check before a builder exports an Agent OS Harness packet.
4+
5+
It does not call Agoragentic, provision infrastructure, run inference, fund treasury, or publish marketplace listings.
6+
7+
## Run
8+
9+
```bash
10+
node micro-ecf/simulator/run.mjs \
11+
--policy micro-ecf/policy.example.json \
12+
--task micro-ecf/simulator/task.example.json
13+
```
14+
15+
The report checks:
16+
17+
- required Micro ECF policy sections
18+
- requested tools against allowed and denied tool policy
19+
- estimated spend against budget and approval thresholds
20+
- side-effect approval posture
21+
- first-proof requirement before public exposure
22+
23+
If the report returns `ok: true`, the next step is:
24+
25+
```bash
26+
node micro-ecf/export-agent-os-harness.mjs \
27+
--policy micro-ecf/policy.example.json \
28+
--output ./agent-os-harness.packet.json
29+
```

micro-ecf/simulator/run.mjs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#!/usr/bin/env node
2+
import fs from 'node:fs';
3+
import path from 'node:path';
4+
import { fileURLToPath } from 'node:url';
5+
6+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
7+
const DEFAULT_POLICY = path.join(__dirname, '..', 'policy.example.json');
8+
const DEFAULT_TASK = path.join(__dirname, 'task.example.json');
9+
10+
const REQUIRED_SECTIONS = [
11+
'agent_manifest',
12+
'context_policy',
13+
'tool_policy',
14+
'budget_policy',
15+
'approval_policy',
16+
'memory_policy',
17+
'swarm_policy',
18+
'deployment_policy',
19+
];
20+
21+
function parseArgs(argv) {
22+
const args = {
23+
policy: DEFAULT_POLICY,
24+
task: DEFAULT_TASK,
25+
};
26+
27+
for (let i = 0; i < argv.length; i += 1) {
28+
const arg = argv[i];
29+
if (arg === '--policy') args.policy = argv[++i];
30+
else if (arg === '--task') args.task = argv[++i];
31+
else if (arg === '--help' || arg === '-h') {
32+
printHelp();
33+
process.exit(0);
34+
} else {
35+
throw new Error(`Unknown argument: ${arg}`);
36+
}
37+
}
38+
39+
return args;
40+
}
41+
42+
function printHelp() {
43+
console.log(`Usage:
44+
node micro-ecf/simulator/run.mjs --policy micro-ecf/policy.example.json --task micro-ecf/simulator/task.example.json
45+
46+
The simulator is local and no-spend. It validates a Micro ECF policy against one proposed task and prints pass/warn/fail checks.
47+
`);
48+
}
49+
50+
function readJson(filePath) {
51+
const resolved = path.resolve(filePath);
52+
return {
53+
resolved,
54+
value: JSON.parse(fs.readFileSync(resolved, 'utf8')),
55+
};
56+
}
57+
58+
function asList(value) {
59+
return Array.isArray(value) ? value : [];
60+
}
61+
62+
function add(checks, level, check, message, details = undefined) {
63+
checks.push({ level, check, message, ...(details === undefined ? {} : { details }) });
64+
}
65+
66+
function simulate(policy, task) {
67+
const checks = [];
68+
const toolPolicy = policy.tool_policy || {};
69+
const budgetPolicy = policy.budget_policy || {};
70+
const approvalPolicy = policy.approval_policy || {};
71+
const deploymentPolicy = policy.deployment_policy || {};
72+
73+
for (const section of REQUIRED_SECTIONS) {
74+
if (policy[section] && typeof policy[section] === 'object' && !Array.isArray(policy[section])) {
75+
add(checks, 'pass', `section.${section}`, `${section} is present`);
76+
} else {
77+
add(checks, 'fail', `section.${section}`, `${section} must be an object`);
78+
}
79+
}
80+
81+
const requestedTools = asList(task.requested_tools);
82+
const allowedTools = asList(toolPolicy.allowed_tools);
83+
const deniedTools = new Set(asList(toolPolicy.denied_tools));
84+
const deniedRequestedTools = requestedTools.filter((tool) => deniedTools.has(tool));
85+
const unknownRequestedTools = requestedTools.filter((tool) => !allowedTools.includes(tool) && !deniedTools.has(tool));
86+
87+
if (deniedRequestedTools.length > 0) {
88+
add(checks, 'fail', 'tools.denied_requested', 'Task requests tools explicitly denied by policy', deniedRequestedTools);
89+
} else {
90+
add(checks, 'pass', 'tools.denied_requested', 'Task does not request denied tools');
91+
}
92+
93+
if (unknownRequestedTools.length > 0) {
94+
add(checks, 'warn', 'tools.unknown_requested', 'Task requests tools not listed in allowed_tools', unknownRequestedTools);
95+
} else {
96+
add(checks, 'pass', 'tools.unknown_requested', 'Requested tools are covered by allowed_tools or denied_tools');
97+
}
98+
99+
const estimatedCost = Number(task.estimated_cost_usdc || 0);
100+
const maxDailySpend = Number(budgetPolicy.max_daily_spend_usdc || 0);
101+
const approvalAbove = Number(budgetPolicy.approval_required_above_usdc || 0);
102+
103+
if (budgetPolicy.treasury_required !== true) {
104+
add(checks, 'fail', 'budget.treasury_required', 'treasury_required must be true before Agent OS autonomous spend');
105+
} else {
106+
add(checks, 'pass', 'budget.treasury_required', 'Treasury funding is required before autonomous spend');
107+
}
108+
109+
if (estimatedCost > maxDailySpend) {
110+
add(checks, 'fail', 'budget.estimated_cost', 'Estimated task cost exceeds max_daily_spend_usdc', { estimatedCost, maxDailySpend });
111+
} else {
112+
add(checks, 'pass', 'budget.estimated_cost', 'Estimated task cost is inside the daily budget', { estimatedCost, maxDailySpend });
113+
}
114+
115+
if (approvalAbove > 0 && estimatedCost > approvalAbove) {
116+
add(checks, 'warn', 'approval.threshold', 'Task exceeds approval_required_above_usdc and should stop for owner approval', { estimatedCost, approvalAbove });
117+
} else {
118+
add(checks, 'pass', 'approval.threshold', 'Task does not exceed the approval threshold', { estimatedCost, approvalAbove });
119+
}
120+
121+
const sideEffects = String(task.side_effects || 'none');
122+
const humanGated = new Set(asList(approvalPolicy.human_gated));
123+
if (sideEffects !== 'none' && toolPolicy.side_effects !== 'approval_required') {
124+
add(checks, 'fail', 'approval.side_effects', 'Side-effecting tasks must require approval');
125+
} else if (sideEffects !== 'none' && !humanGated.has(sideEffects)) {
126+
add(checks, 'warn', 'approval.side_effects', 'Side effect is not listed in approval_policy.human_gated', sideEffects);
127+
} else {
128+
add(checks, 'pass', 'approval.side_effects', 'Side-effect policy is explicit for this task');
129+
}
130+
131+
if (deploymentPolicy.first_proof_required === false) {
132+
add(checks, 'fail', 'deployment.first_proof', 'first_proof_required should stay true for Agent OS handoff');
133+
} else {
134+
add(checks, 'pass', 'deployment.first_proof', 'First proof is required before public exposure');
135+
}
136+
137+
const failCount = checks.filter((entry) => entry.level === 'fail').length;
138+
const warnCount = checks.filter((entry) => entry.level === 'warn').length;
139+
140+
return {
141+
ok: failCount === 0,
142+
schema: 'agoragentic.micro-ecf.simulation.v1',
143+
summary: {
144+
pass: checks.filter((entry) => entry.level === 'pass').length,
145+
warn: warnCount,
146+
fail: failCount,
147+
no_spend: true,
148+
},
149+
next_step: failCount === 0
150+
? 'Export an Agent OS Harness packet with micro-ecf/export-agent-os-harness.mjs'
151+
: 'Fix failed policy checks before exporting the Agent OS Harness packet',
152+
checks,
153+
};
154+
}
155+
156+
function main() {
157+
const args = parseArgs(process.argv.slice(2));
158+
const policy = readJson(args.policy);
159+
const task = readJson(args.task);
160+
const report = simulate(policy.value, task.value);
161+
report.generated_from = {
162+
source: 'micro-ecf/simulator/run.mjs',
163+
policy_path: path.relative(process.cwd(), policy.resolved).replace(/\\/g, '/'),
164+
task_path: path.relative(process.cwd(), task.resolved).replace(/\\/g, '/'),
165+
};
166+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
167+
process.exit(report.ok ? 0 : 1);
168+
}
169+
170+
try {
171+
main();
172+
} catch (err) {
173+
console.error(JSON.stringify({ ok: false, error: err.message }, null, 2));
174+
process.exit(1);
175+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "qualified partner lead research",
3+
"requested_tools": [
4+
"web_search",
5+
"marketplace_execute"
6+
],
7+
"estimated_cost_usdc": 1.25,
8+
"side_effects": "none",
9+
"expected_output": "A reviewed shortlist of possible partners and outreach notes"
10+
}

0 commit comments

Comments
 (0)