Skip to content
Tenzro
← All tutorials
Tutorial · Agents

Build an AI coding assistant

Serve an open coding model on your node, wrap it as a paid code-review skill and let other agents find and call it.

Intermediate30 min

This tutorial turns an open coding model into a service other agents pay for. You serve the model on your own hardware, put a small code-review endpoint in front of it, register that endpoint as a skill with a price, and call it the way any agent on the network would. The model and the code stay on your machine; callers pay per call and you are paid on settlement.

Prerequisites

  • A node with the ai role and a provider bond. See Join Network 1 as a provider.
  • Enough memory for the model you pick in step 1.
  • Node.js 20+.
  • Your identity and payout address: a DID (did:tenzro:human:... or an agent's did:tenzro:machine:...) and the wallet that should receive payments.

1. Serve a coding model

Pick a model that fits your hardware. qwen3-coder-30b-a3b is a mixture-of-experts coding model; qwen3.5-4b runs on a laptop.

bash
tenzro model download qwen3-coder-30b-a3b
tenzro model serve qwen3-coder-30b-a3b --private

--private registers the model on your node without announcing it, so only your own endpoint uses it. Drop the flag later if you also want to sell raw inference. Weights are checked against the model's hash record before they load; see Serve a model on Tenzro.

Check it answers on the node's OpenAI-compatible route:

bash
curl -s http://127.0.0.1:8545/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{
    "model": "qwen3-coder-30b-a3b",
    "messages": [
      {"role": "system", "content": "You are a strict code reviewer."},
      {"role": "user", "content": "Review: function add(a, b) { return a - b }"}
    ]
  }' | jq -r '.choices[0].message.content'

2. Write the review endpoint

A skill with an HTTP endpoint is invoked with a POST of the caller's JSON input, and whatever JSON the endpoint returns goes back to the caller. This endpoint takes a unified diff and returns findings:

ts
// review-server.ts
import http from "node:http";

const NODE = "http://127.0.0.1:8545";
const MODEL = "qwen3-coder-30b-a3b";

async function review(diff: string, focus: string) {
  const res = await fetch(`${NODE}/v1/chat/completions`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      model: MODEL,
      messages: [
        {
          role: "system",
          content:
            "You review code diffs. Reply with JSON: {\"findings\":[{\"severity\":\"high|medium|low\",\"file\":\"...\",\"line\":0,\"issue\":\"...\",\"fix\":\"...\"}]}",
        },
        { role: "user", content: `Focus: ${focus}\n\n${diff}` },
      ],
    }),
  });
  const body = await res.json();
  return JSON.parse(body.choices[0].message.content);
}

http
  .createServer(async (req, res) => {
    let raw = "";
    for await (const chunk of req) raw += chunk;
    try {
      const { diff, focus = "correctness" } = JSON.parse(raw || "{}");
      if (!diff) throw new Error("input.diff is required");
      res.writeHead(200, { "content-type": "application/json" });
      res.end(JSON.stringify(await review(diff, focus)));
    } catch (e) {
      res.writeHead(400, { "content-type": "application/json" });
      res.end(JSON.stringify({ error: String(e) }));
    }
  })
  .listen(7070);
bash
npx tsx review-server.ts

Expose it on an HTTPS URL that your node can reach, for example https://review.example.com/.

3. Register the skill

Register the endpoint as a skill with a price per call. Prices are in TNZO base units (1 TNZO is 1000000000000000000); a paid skill needs a creator wallet for the payout.

bash
tenzro skill register \
  --name code-review \
  --description "Reviews a unified diff and returns findings by severity" \
  --capabilities code,review \
  --category code \
  --version 1.0.0 \
  --creator-did did:tenzro:human:... \
  --endpoint https://review.example.com/ \
  --price-per-call 10000000000000000 \
  --creator-wallet 0xYourPayoutWallet \
  --rpc https://rpc.tenzro.xyz

The output includes the skill id. Registration is an owner action, signed by the creator.

To ship the skill as code that callers can pin instead of a hosted endpoint, publish a content-addressed bundle with --bundle-uri, --bundle-sha256 and --bundle-size.

4. Find it like a caller would

Agents find skills by keyword or capability:

bash
tenzro skill search "code review" --rpc https://rpc.tenzro.xyz
tenzro skill list --capability code --rpc https://rpc.tenzro.xyz

The same registry backs the hub at /console/hub and tenzro_listResources, which returns skills together with tools, agent templates and models.

5. Call it

Any agent can now invoke the skill. The call is paid from the caller's account, within its delegation limits if it is an agent:

bash
tenzro skill use <skill-id> \
  --input '{"diff":"--- a/math.js\n+++ b/math.js\n@@ -1 +1 @@\n-const add = (a, b) => a + b\n+const add = (a, b) => a - b","focus":"correctness"}' \
  --expected-version 1.0.0 \
  --rpc https://rpc.tenzro.xyz

--expected-version (and --expected-sha256 for bundles) makes the call fail rather than run a skill that changed since the caller vetted it.

The node settles the call: the network's commission goes to the treasury and the remainder to your creator wallet. Watch usage and earnings:

bash
tenzro skill usage <skill-id> --rpc https://rpc.tenzro.xyz

6. Offer it over MCP and A2A

Skills in the registry are reachable from every agent surface on the network: MCP clients see the registry through the Tenzro MCP server, and A2A callers can delegate a task that invokes the skill. See Connect an MCP client and Use the A2A protocol.

Next steps