Build on Anna 102_Tool&Executa

261008_Build on Anna 102_Tool&Executa

Hello, Executa! Adding a Backend to Your Anna App

0. Want to Check Your App First? Hand the Guide to Your Agent

If you want to understand what specifications the Anna platform requires for Apps with backend Tool Executas, feel free to read on. We will explain the key requirements using a minimal example.

If you find the content below too long or want to inspect your own project directly, you can hand the companion AI Agent Pre-Release Inspection Guide to your Agent. The guide has already organized the official specifications, inspection sequence, test methods, and report templates, allowing the Agent to execute directly without searching through official documentation.

You can instruct it like this:

Please read the provided "Anna App Pre-Release Inspection Guide: For AI Agent Execution",
and inspect my Anna App project according to the discovery, configuration, protocol, artifact,
and frontend invocation checklist items in the guide: <fill in absolute path to project>.

Inspect tools, methods, parameters, and release platforms one by one, retain evidence,
and output an inspection report following the guide's template. Explain identified issues,
specific modification recommendations, and items pending verification.
Mark unexecuted checks or checks lacking required conditions as BLOCKED; do not count them as passed.
For this run, only inspect and report; do not execute a release.

Verifying applicable items to a pass status helps discover and prevent common issues with reference configurations, describe formatting, and release archive entrypoints early, reducing cloud Agent installation or loading failures. The report will also clearly distinguish between local checks and cloud verifications; artifacts not yet run on the target platform, unverified authorizations, or cloud installations require further verification before they can be considered fully passed.

1. Background: Getting Backend Tools to Run Smoothly on Anna

When developing an App with backend tools for Anna, many developers encounter an issue: the App’s frontend is ready, and the backend code runs fine on their local machine, but after release, the backend tool fails to install on the cloud Agent, or fails to start and be invoked properly after installation.

A primary cause of such issues is that the tool was not configured, implemented, and packaged according to the Anna platform’s specifications. From local development to running on a cloud Agent, the platform needs to know which tool the App depends on, which platform’s binary should be downloaded, where to start execution after extraction, and how to identify and invoke this tool. Every step has corresponding conventions; a mismatch in configuration or protocol can break the entire invocation chain.

This tutorial uses a minimal App to string these requirements into a workflow you can follow step-by-step.

The example has only one page and one button. Clicking the button causes the frontend to invoke a backend method get_types written in Go. The backend returns a JSON object, and the frontend displays sample values corresponding to six parameter types: string, integer, number, boolean, array, and object. The frontend uses native HTML, CSS, and JavaScript, while the backend relies solely on the Go standard library. Binaries for various platforms can also be cross-compiled and packaged on your own machine.

Keeping the functionality simple makes configuration files and tool protocols easier to examine clearly. Next, we will focus on explaining app.json, the App’s manifest.json, and the response requirements of describe, showing how the App links with the tool and how the cloud Agent identifies the methods provided by the tool. After reading, you can check your own App against the example to avoid installation and loading failures caused by non-compliant configuration or description formats.

2. Meet the Example: One Button, One Backend Tool

The explanations below all use Anna Type Demo as an example. The complete code is available on GitHub: anna-app-tool-starter, which you can reference alongside this guide.

2.1 What Does This App Do?

Open the App, and the page features only a Get backend data button and a table displaying results. After clicking the button, the frontend invokes the backend’s get_types method to obtain six sample fields corresponding to string, integer, number, boolean, array, and object. The page displays the values of these fields and allows expanding them to view the complete JSON.

This method is provided by a Tool Executa named type-demo, written in Go. The frontend handles initiating invocations and displaying results, while the backend handles processing requests and returning data. This small feature connects the invocation flow between the App and the backend tool. We will follow this flow to see what configuration and protocol conventions Anna requires.

2.2 Where Are the Key Files?

First, look at the files directly related to this flow in the project:

anna-app-tool-starter/
├── app.json                    # App basic info and tool directories bundled with the App
├── manifest.json               # App UI configuration, tool dependencies, and invocation permissions
├── bundle/
│   ├── index.html              # Page structure: button, table, and JSON display area
│   ├── app.js                  # Invoke tool via Anna SDK and display returned values
│   └── app.css                 # Page styles
├── executas/type-demo/
│   ├── executa.json            # Tool's local startup method and binary distribution configuration
│   ├── manifest.json           # Tool description, method, and parameter definitions returned by describe
│   └── main.go                 # Go backend: handles protocol requests, implements get_types
└── scripts/
    └── build-binary.go          # Cross-compile locally and generate binary distribution packages

There are two manifest.json files here, and their purposes must be distinguished: the one in the root directory describes the App, while the one in the tool directory describes the Tool Executa. The former declares how the page opens, which tools the App depends on, and which tools the frontend can invoke; the latter lets Anna know what methods the tool provides and what parameters each method accepts.

Subsequent sections will focus on explaining the linking configuration between the App and the tool, as well as the response requirements of describe. The next section begins with app.json and the App’s manifest.json to see how to properly link the App with the backend tool.

3. Writing Configuration Correctly: Letting the App Find the Backend Tool

Anna needs to know: where the App’s page is, which backend tool it depends on, and which tool the frontend needs to invoke. We connect this information using several configuration snippets from the example.

3.1 Declare the Tool Directory in app.json

The bundled_executas field in app.json is used to declare tools released alongside the App. The configuration in the example is:

{
  "bundled_executas": {
    "type-demo": {
      "path": "executas/type-demo"
    }
  }
}

Here, type-demo is the reference name we assigned to the tool, which will be used in subsequent configurations and frontend code. path resolves relative to the project root directory, pointing to the folder where the tool resides; this folder contains executa.json, which describes the tool’s startup and distribution methods.

3.2 Declare Pages and Tool Dependencies in App manifest

Next, look at manifest.json in the root directory. Below, configuration relevant to this section is retained while settings such as window dimensions are omitted:

{
  "schema": 2,
  "required_executas": [
    { "tool_id": "bundled:type-demo", "min_version": "0.1.0", "version": "latest" }
  ],
  "ui": {
    "bundle": {
      "format": "static-spa",
      "entry": "index.html",
      "external_origins": []
    },
    "views": [
      { "name": "main", "title": "Anna Type Demo", "default": true }
    ],
    "host_api": {
      "tools": ["required:bundled:type-demo"]
    }
  }
}

Key points in this configuration:

  • Dependencies: required_executas declares tools essential to the App, which are automatically installed when installing the App. bundled:type-demo references type-demo from app.json. The version: "latest" here will be frozen into a concrete tool version upon release.
  • Invocation Scope: ui.host_api.tools explicitly designates the tools the frontend is permitted to invoke. required:bundled:type-demo indicates permission to invoke the required tool declared above.

Note that bundled:type-demo is a local reference syntax used by the Anna CLI. Upon release, the CLI resolves it to a real tool ID on the platform.

3.3 Frontend Obtains Tool ID via Mapping

Once configuration is linked, the frontend also uses the same reference name. After the Anna SDK completes connection, the critical part of the invocation code is:

const toolId = window.__ANNA_TOOL_IDS__["type-demo"];

const data = await anna.tools.invoke({
  tool_id: toolId,
  method: "get_types",
  args: {},
});

window.__ANNA_TOOL_IDS__ is provided by anna-tool-ids.js generated by the CLI, which the page loads first. The frontend uses type-demo to retrieve the tool ID for the current environment, then invokes the get_types method it provides. Thus, both development and release obtain IDs through the same mapping.

When checking these configurations, first confirm that the type-demo reference name is consistent across app.json, the App manifest, and frontend code, then confirm that the tool directory and page entrypoint genuinely exist.

Next, we look into the tool itself to see what describe should return so that the Agent correctly identifies the methods and parameters provided by the tool.

4. Writing describe Correctly: Letting the Agent Recognize Your Tool

A backend tool returning a describe that does not conform to the Anna protocol is one of the main reasons such Apps fail to install or load on an Agent.

After downloading and starting the tool, the Agent also needs to learn via describe what methods the tool provides and what parameters each method accepts. If the returned format is incorrect, the Agent cannot properly recognize the tool, and subsequent invocations cannot proceed normally.

4.1 What Format Must describe Return?

The Agent sends a JSON-RPC request via standard input (stdin), for example:

{"jsonrpc":"2.0","id":1,"method":"describe"}

The tool must return a JSON-RPC response via standard output (stdout). result must directly be the tool’s manifest object. Below is the complete response for this example:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "name": "type-demo",
    "display_name": "Anna Type Demo",
    "version": "0.1.0",
    "description": "Return one field for each of Anna's six supported parameter types. Omitted arguments use the declared defaults.",
    "tools": [
      {
        "name": "get_types",
        "description": "Return string, integer, number, boolean, array and object sample values. Optionally override any sample with a value of the declared type.",
        "parameters": [
          { "name": "string_value", "type": "string", "description": "A string sample.", "required": false, "default": "Hello, Anna!" },
          { "name": "integer_value", "type": "integer", "description": "An integer sample.", "required": false, "default": 42 },
          { "name": "number_value", "type": "number", "description": "A number sample.", "required": false, "default": 3.14 },
          { "name": "boolean_value", "type": "boolean", "description": "A boolean sample.", "required": false, "default": true },
          { "name": "array_value", "type": "array", "items_type": "string", "description": "An array of strings.", "required": false, "default": ["Anna", "Go", "Executa"] },
          { "name": "object_value", "type": "object", "description": "A JSON object sample.", "required": false, "default": { "platform": "Anna", "language": "Go" } }
        ],
        "timeout": 10
      }
    ],
    "credentials": [],
    "host_capabilities": [],
    "runtime": { "type": "binary" }
  }
}

The outer jsonrpc is fixed as "2.0", id must correspond as-is to the ID in the request, and the tool description is placed in result. Do not wrap another manifest layer inside result, nor wrap success / data. success / data is the business response structure for invoke.

The JSON above is indented for readability. During actual communication, the entire response must be encoded as a single-line UTF-8 JSON, terminated with a newline character \n.

4.2 What Content Does the Tool Description Support?

First, look at the main fields at the top level of the manifest:

Field Required? Purpose
name No Can be retained as an explanatory or diagnostic label; tool identity is managed by the platform-generated tool_id
version Yes Tool version, using SemVer format such as 0.1.0
description Yes Explains the purpose of the overall tool
tools Yes List of method definitions, containing at least one method
display_name No, recommended User-facing display name
credentials As needed Declares credentials requiring user configuration; this example uses [] indicating no credentials needed
host_capabilities As needed Required when using corresponding host capabilities; this example uses [] indicating these capabilities are not needed
runtime No Runtime hint; this example fills in { "type": "binary" }

The top-level name can be omitted. Under Anna’s current tool identity mechanism, the platform is responsible for generating and passing tool_id, which the Agent uses to associate installation records with running tools. This example retains name: "type-demo" as an explanatory label. This behavior can be cross-referenced with the official Tool Release Guide and Focus Flow Example Documentation.

Introductory information such as author, homepage, icon, category, and license may also be provided.

Each object in tools describes an invokable method: tools[].name and description here remain required, and method names must be unique within the same tool; parameters is an optional parameter list, which can be [] when there are no parameters; timeout is the invocation timeout in seconds, defaulting to 60 seconds, set to 10 seconds in this example. The protocol also supports a streaming field, but it is currently a reserved feature.

Here, tools[0].name: "get_types" must match the frontend-invoked method: "get_types" as well as the method name actually handled by the backend. Method descriptions and parameter descriptions also help the Agent judge when to invoke and what values should be passed.

If the tool requires an API Key, credentials declares information such as the credential’s name, description, whether it is required, and whether it is sensitive; the actual value is placed by the Agent in params.context.credentials during invocation. If capabilities such as LLM sampling or storage are needed, host_capabilities must use capability names supported by Anna, such as llm.sample; corresponding features also require completing capability negotiation. Both lists can simply be kept empty for this example.

4.3 Parameters Support Only These Six Types

When declaring parameters, it must be written as a list according to Anna’s format, where each parameter is an object in the list. The parameter’s type supports the following six values:

type Meaning Sample JSON Value
string String "Hello, Anna!"
integer Integer 42
number Number, can contain decimals 3.14
boolean Boolean true
array Array ["Anna", "Go"]
object JSON Object {"platform":"Anna"}

Each parameter uses name to specify the parameter name, description to explain its meaning, and can add constraints through these fields:

  • required: Whether it is required; defaults to true when omitted. The example explicitly sets it to false, allowing callers to omit these parameters.
  • default: Declares a default value; the value’s type should match type. The Go backend in the example reads these declarations and uses default values when callers omit parameters.
  • enum: Restricts allowed values; for example, a string parameter can declare "enum": ["small", "large"]. The backend implementation should also validate parameters according to declarations.
  • items_type or items: Specifies array element types. This example uses "items_type": "string"; the protocol also supports "items": {"type": "string"}. Choose either syntax.

These types are used to declare input parameters. This example places the values of the six parameters into the returned JSON, so the page can also display samples of the six types. null is a JSON value, but does not belong to the independent parameter types listed above.

Do not write type names as Go’s int, float64, or bool. Nor should you replace parameters with MCP-style inputSchema / input_schema, or write the entire parameters as a JSON Schema object with properties; doing so prevents the Agent from reading them according to Anna’s parameter format.

4.4 How Does the Backend Implement describe?

This example uses Go for the convenience of cross-compiling and packaging binaries. Regardless of which language is used, implementing describe follows the exact same protocol.

The tool description can be written directly in code, or stored separately as a manifest.json. Storing it separately facilitates maintenance and reuse; the program can read it at runtime, or embed the description into the artifact at build time. The protocol cares about the actual returned JSON format; the method of storing descriptions is chosen by the developer.

Below is pseudocode for the processing flow:

tool_description = construct object in code, or read and parse JSON from file

loop read each line from stdin:
    request = parse JSON
    if request.method == "describe":
        response = {
            "jsonrpc": "2.0",
            "id": request.id,
            "result": tool_description
        }
        encode response as single-line JSON, write to stdout, and append "\n"
        flush stdout

The key is to ensure the result received by the Agent is a JSON object. When using a JSON encoder, place the description object directly into result, then encode the entire response; string content such as quotes and newlines within the description will be escaped by the encoder according to JSON rules. Do not encode the entire description into a string first and then place that string into result, otherwise what the Agent reads will be a string.

If the program reads an external description file at runtime, ensure that the file is distributed alongside the tool and that the program can locate it on the Agent. If the description is embedded into the binary, rebuilding is required after modifications. Whichever method is adopted, the content returned by the actual describe should remain consistent with the published tool description.

The process and output must also adhere to three requirements:

  • stdout writes only protocol messages; logs go to stderr. Each response is output as a single line of JSON, terminated with \n.
  • Return promptly and flush output. describe is only responsible for returning descriptions; move time-consuming business operations into invoke to avoid the Agent timing out while waiting for a response.
  • Continue reading stdin after returning. The tool needs to remain running and process subsequent requests, exiting when stdin closes. Exiting immediately after returning describe once causes the Agent to mark the tool as stopped.

4.5 The Most Error-Prone Areas

When encountering installation, loading, or invocation failures, you can check against these first:

Common Mistake Correct Practice
Extra manifest or success / data wrapper inside result Place the tool manifest directly inside result
result is a JSON string Place the description object directly into result, then encode the entire response
Replacing parameters with input_schema, or writing the parameter list as an object Use Anna’s parameters list format
Parameter types written as int, float, bool, etc. Use the six protocol type names listed above
Response IDs do not match, or a single response spans multiple lines Return request IDs as-is; each response occupies one line ending with \n
Exiting immediately after returning describe Maintain the request loop and continue processing subsequent calls

If you need to inspect the actual description of the example, you can run in the project:

npm run tool:describe

This command invokes the backend’s describe. The CLI outputs the manifest unwrapped from the outer JSON-RPC envelope for easier reading. When communicating with the Agent, the tool still requires the complete JSON-RPC response format.

For a more comprehensive check, you can run npm run check, which also verifies whether the packaged local binary correctly returns descriptions and continuously processes subsequent requests.

References: Tool Executa Protocol, Lifecycle and Capability Negotiation.

5. Before Release, Verify These Three Key Points

When encountering a tool failing to install or load on a cloud Agent, you can check against this article first:

  1. Is the tool directory in app.json correct? The path in bundled_executas must point to the actual tool directory, and the reference name must match the App manifest and frontend code.
  2. Does the App’s manifest.json link the tool correctly? Verify the page entrypoint, dependencies in required_executas, and invocation scope in ui.host_api.tools. When using bundled references, let the CLI resolve tool IDs and make them available to the frontend via the generated mapping.
  3. Does describe return a protocol-compliant tool description? Place the manifest object directly in result, align method names with actual implementations, use the list format for parameters, and use the six type names supported by Anna. The published description must also remain consistent with what the program actually returns.

During communication, also maintain single-line JSON, promptly flush output, write logs to stderr, and continue processing requests after returning responses. The top-level name of the tool can be omitted, but tools[].name must still be filled in correctly.

For binary packaging and multi-platform distribution, continue reading 7. Build Executa Multi-platform Binaries using GitHub Actions in Build on Anna 101. This example repository also provides a local cross-compilation script, making it convenient for developers using Go to generate distribution packages directly.

Complete sample code: anna-app-tool-starter.