Public beta — not for production use. Data may be wiped at any time. Questions? Contact us.
Documentation menu

Import message types from another package

Find a published package with axiom search and axiom info, pull its message types into your package with axiom import, and use them as node inputs and outputs.

View as Markdown

Every node input and output is a message — a Protocol Buffers type. Messages do not have to be defined in your own package: axiom import downloads the .proto definitions from any published package so your nodes can consume or produce its types. This is how packages — even in different languages — share a contract: a flow can wire another package's node output straight into your node's input because both sides reference the same message type. See the type system for how edges type-check.

Prerequisites

  • An Axiom package directory (one containing axiom.yaml) — create one with axiom init, see write your first node.
  • Logged in via axiom login. axiom import requires it; axiom search and axiom info work without authentication.
  • For Go, Python, and TypeScript packages, axiom import finishes by running axiom generate, which uses the same proto tooling as the rest of the local loop (protoc + protoc-gen-go for Go; grpcio-tools or protoc for Python; protoc + protoc-gen-js + protoc-gen-ts for TypeScript). Rust, Java, and C# packages need no extra tooling — their protos compile during the language build.

The fast path

# Run inside your package directory (where axiom.yaml is).
axiom search --type messages TokensResult   # which package defines the type?
axiom info axiom-official/axiom-text-ops    # inspect its nodes and messages
axiom import axiom-official/axiom-text-ops  # download protos, update axiom.yaml, generate
axiom create node Analyze --input TokensResult --output AnalysisReport

After axiom import, the imported message types appear in axiom create node's message list and work as --input/--output exactly like messages defined in your own messages/messages.proto.

Search the marketplace

axiom search queries the marketplace; no login is needed.

axiom search                                # list recently published packages
axiom search text-ops                       # packages matching "text-ops"
axiom search --type nodes "tokenize"        # search nodes instead
axiom search --type messages TokensResult   # search messages instead

--type (shorthand -t) selects what to search: packages (the default), nodes, or messages. Package results list name, version, language, node count, and author. Node and message results include the package and version that publish them — so --type messages answers "which package do I import to get this type?"

Inspect a package before importing

axiom info shows the full details of a published package; no login is needed.

axiom info axiom-official/axiom-text-ops        # most recently published version
axiom info axiom-official/axiom-text-ops@0.1.0  # a specific version

When @version is omitted, the most recently published version is shown. The output includes the description, author, license, and deploy status; the package's live endpoint URL; links to its openapi.json and interactive API docs (see use the interactive API docs); every node with its input → output message types; and every message the package defines — the names you can use after importing.

A package can be proto-only: no nodes, just message types published for other packages to import. See nodes, packages, and flows.

Import the message types

# Run inside your package directory (where axiom.yaml is).
axiom import axiom-official/axiom-text-ops        # latest version
axiom import axiom-official/axiom-text-ops@0.1.0  # pinned version

axiom import requires a prior axiom login and must run inside a package directory. It does four things:

  1. Resolves the version (the most recently published one when @version is omitted) and downloads the package's .proto files.
  2. Extracts them to imports/<package>/<version>/. A scoped name's / becomes - in the directory name, so axiom-official/axiom-text-ops@0.1.0 lands in imports/axiom-official-axiom-text-ops/0.1.0/.
  3. Records the dependency in axiom.yaml under imports: with the package, version, and imported message names.
  4. Runs axiom generate so the language bindings appear under gen/ immediately.

If an imported message has the same name as one in your local messages/, the import fails with a collision error before writing anything — rename one of the two first.

Commit imports/ and the updated axiom.yaml to your repository: axiom push builds your package from your git remote's HEAD commit, not your working tree, so unpushed import files would be missing from the build.

What axiom import writes

After importing, axiom.yaml carries the pinned dependency:

# axiom.yaml (excerpt written by axiom import)
imports:
    - package: axiom-official/axiom-text-ops
      version: 0.1.0
      messages:
        - TextRequest
        - TokensResult

and the raw proto definitions live in your repository. The registry names each downloaded file after the first message it defines (snake_case), not after the upstream file name — here the package's TextRequest and TokensResult share one proto file, downloaded as text_request.proto:

imports/
└── axiom-official-axiom-text-ops/
    └── 0.1.0/
        └── text_request.proto

Each entry pins an exact version. Re-running the same import is safe — it merges any newly published message names into the existing entry. Importing a different version of the same package adds a second entry and a second directory side by side; nothing is upgraded implicitly.

Where the generated bindings go

  • Gogen/imports/<package>/<version>/ (Go protobuf bindings).
  • Python — one module per imported package, named after it: gen/axiom_official_axiom_text_ops_messages_pb2.py for the example above.
  • TypeScriptgen/imports/<package>/<version>/, one <file>_pb.js plus a <file>_pb.d.ts type surface per downloaded proto file: text_request_pb.js and text_request_pb.d.ts for the example above.
  • Rust, Java, C# — nothing at import time; the protos compile during the language build (build.rs/tonic-build for Rust, the protobuf-maven-plugin for Java, Grpc.Tools for C#).

Use an imported message in a node signature

Reference imported messages by their simple name, exactly like local ones. axiom create node lists them in its interactive message picker alongside local messages, accepts them for --input/--output, and prints a note about their origin:

# Run inside your package directory, after axiom import.
axiom create node Analyze --input TokensResult --output AnalysisReport
# Note: TokensResult is from imported package "axiom-official-axiom-text-ops@0.1.0"

The node's entry in axiom.yaml uses the simple name (input: TokensResult); Axiom resolves which package it comes from via the imports: section. For Go, Python, Java, C#, and Rust, the scaffolded node file already contains the correct import statement. For TypeScript, the scaffold always imports from ../gen/messages_pb (the local messages module) — edit that line to point at the imported module path shown below.

A complete Go example

A Go node whose input type comes from the imported package and whose output type is local. Replace axiom-analytics with the module path from your package's go.mod:

// nodes/analyze.go — input imported from axiom-official/axiom-text-ops
package nodes

import (
	"context"
	"fmt"
	"strings"

	"axiom-analytics/axiom"
	gen "axiom-analytics/gen"
	axiomtextops "axiom-analytics/gen/imports/axiom-official-axiom-text-ops/0.1.0"
)

// Analyze accepts tokenized text and produces a summary report with the
// token count and a human-readable listing of the tokens.
func Analyze(ctx context.Context, ax axiom.Context, input *axiomtextops.TokensResult) (*gen.AnalysisReport, error) {
	return &gen.AnalysisReport{
		Summary:   fmt.Sprintf("Processed %d tokens: %s", input.GetCount(), strings.Join(input.GetTokens(), ", ")),
		WordCount: input.GetCount(),
	}, nil
}

Import statements per language

For a message TokensResult imported from axiom-official/axiom-text-ops@0.1.0:

# nodes/analyze.py — Python: per-package module under gen/
from gen.axiom_official_axiom_text_ops_messages_pb2 import TokensResult
// nodes/analyze.ts — TypeScript: module under gen/imports/, named after the proto file
import { TokensResult } from '../gen/imports/axiom-official-axiom-text-ops/0.1.0/text_request_pb';
// nodes/analyze.rs — Rust: imported messages compile into the same module as local ones
use crate::gen::messages::TokensResult;
// nodes/Analyze.java — Java: fully qualified type in the imports.* namespace
import imports.axiom_official.axiom_text_ops.TokensResult;
// nodes/analyze.cs — C#: bring in the imports.* namespace, then use the simple name
using imports.axiom_official.axiom_text_ops;

Java and C# derive the namespace from the package name: / becomes . and - becomes _, so axiom-official/axiom-text-ops becomes imports.axiom_official.axiom_text_ops. Local messages stay where they always are: gen.Messages.<Name> in Java, the Gen namespace in C#.

Troubleshooting

  • "message X is listed in axiom.yaml imports but its proto definition is not downloaded"axiom.yaml declares the import but the files under imports/ are missing (for example, a fresh checkout where imports/ was never committed). Run the axiom import <package>@<version> command the error message prints.
  • "import collision: message X exists in both your local messages/ and the imported package" — two messages with the same name cannot coexist. Rename your local message (or import a package that doesn't clash), then re-run the import.
  • "axiom.yaml not found — run this command from an Axiom package directory"axiom import only works inside a package directory; cd into the directory created by axiom init first.
  • "Not logged in" — run axiom login. Search and info work logged out; import does not.

Next steps