Skip to main content
Version: 0.1.34

Publish a package by example (x07-package.json → x07.io)

This page is a step-by-step workflow for creating and publishing an X07 package to the public registry.

It is written to keep the story consistent across:

  • x07 (toolchain)
  • x07lang.org docs
  • x07.io (registry UI)

If you just want the reference flags, see Publishing.

Mental model

Two similar-looking JSON files have different jobs:

  • x07.json — project manifest (apps + local dev). Defines module roots, entrypoint, profiles, dependencies.
  • x07-package.json — package manifest (publish contract). Defines name/version, module root, and which module IDs are included in the artifact.

A package repo will typically contain both:

  • x07-package.json (publish)
  • x07.json (local tests, demos, CI)

Example package: acme-hello-demo

This tutorial publishes a tiny library module plus a published tests module:

  • ext.acme_hello_demo
  • ext.acme_hello_demo.tests

If you are publishing to the public registry, choose a unique package name (for example, include your org/handle).

Companion example (in the x07 repo):

  • docs/examples/tutorials/package_publish_acme_hello_demo/

Step 0: create the skeleton (publish-ready)

mkdir acme-hello-demo
cd acme-hello-demo
x07 init --package

This creates a publish-ready repo:

acme-hello-demo/
.gitignore
AGENT.md
x07-toolchain.toml
x07.json
x07.lock.json
x07-package.json
.agent/
docs/
...
skills/
...
modules/
ext/
acme_hello_demo.x07.json
acme_hello_demo/
tests.x07.json
tests/
tests.json

Step 1: library module

x07 init --package generates modules/ext/acme_hello_demo.x07.json:

{
"schema_version": "x07.x07ast@0.4.0",
"kind": "module",
"module_id": "ext.acme_hello_demo",
"imports": [],
"decls": [
{ "kind": "export", "names": ["ext.acme_hello_demo.hello_v1"] },
{
"kind": "defn",
"name": "ext.acme_hello_demo.hello_v1",
"params": [{ "name": "name", "ty": "bytes_view" }],
"result": "bytes",
"body": [
"begin",
["let", "prefix", ["bytes.concat", ["bytes.lit", "hello,"], ["bytes1", 32]]],
["let", "tmp", ["bytes.concat", "prefix", ["view.to_bytes", "name"]]],
["bytes.concat", "tmp", ["bytes1", 10]]
]
}
]
}

x07 init --package also generates modules/ext/acme_hello_demo/tests.x07.json:

{
"schema_version": "x07.x07ast@0.4.0",
"kind": "module",
"module_id": "ext.acme_hello_demo.tests",
"imports": ["ext.acme_hello_demo", "std.test"],
"decls": [
{ "kind": "export", "names": ["ext.acme_hello_demo.tests.test_hello_v1"] },
{
"kind": "defn",
"name": "ext.acme_hello_demo.tests.test_hello_v1",
"params": [],
"result": "result_i32",
"body": [
"begin",
["let", "name", ["bytes.lit", "x07"]],
["let", "got", ["ext.acme_hello_demo.hello_v1", ["bytes.view", "name"]]],
["let", "expected_prefix", ["bytes.concat", ["bytes.lit", "hello,"], ["bytes1", 32]]],
["let", "expected_tmp", ["bytes.concat", "expected_prefix", "name"]],
["let", "expected", ["bytes.concat", "expected_tmp", ["bytes1", 10]]],
["try", ["std.test.assert_bytes_eq", "got", "expected", ["std.test.code_assert_bytes_eq"]]],
["std.test.pass"]
]
}
]
}

Step 3: package manifest (x07-package.json)

x07 init --package generates a registry-compatible x07-package.json. Publishing to the public registry requires non-empty description and docs.

{
"schema_version": "x07.package@0.1.0",
"name": "acme-hello-demo",
"version": "0.1.0",
"description": "Starter package generated by `x07 init --package`: ext.acme_hello_demo.hello_v1(name) -> bytes.",
"docs": "Starter package generated by `x07 init --package`.\n\nModules:\n- ext.acme_hello_demo\n- ext.acme_hello_demo.tests\n\nUsage:\n- Add: x07 pkg add acme-hello-demo@0.1.0 --sync\n- Import: ext.acme_hello_demo\n- Call: ext.acme_hello_demo.hello_v1\n\nDev:\n- Test: x07 test --manifest tests/tests.json\n- Pack: x07 pkg pack --package . --out dist/acme-hello-demo-0.1.0.x07pkg\n",
"module_root": "modules",
"modules": ["ext.acme_hello_demo", "ext.acme_hello_demo.tests"],
"meta": {
"determinism_tier": "pure",
"worlds_allowed": ["run-os", "run-os-sandboxed"],
"import_mode": "handwritten",
"visibility": "experimental"
}
}

Step 4: tests manifest (tests/tests.json)

x07 init --package generates a CI-friendly tests/tests.json:

{
"schema_version": "x07.tests_manifest@0.1.0",
"tests": [
{ "id": "hello_v1", "world": "run-os", "entry": "ext.acme_hello_demo.tests.test_hello_v1", "expect": "pass" }
]
}

It also generates a minimal x07.json so x07 test can automatically discover module roots:

{
"schema_version": "x07.project@0.3.0",
"world": "run-os",
"entry": "modules/ext/acme_hello_demo/tests.x07.json",
"module_roots": ["modules"],
"lockfile": "x07.lock.json",
"dependencies": []
}

Overrides & advisories (optional)

If a transitive dependency is yanked or has an advisory, you can force a different version via patch:

{
"patch": {
"some-dep": { "version": "1.2.3" }
}
}

When x07 pkg lock consults an index, it records yanked and advisories metadata into x07.lock.json. In CI, x07 pkg lock --check fails on yanked/advised deps unless you explicitly allow them (--allow-yanked / --allow-advisories).

Run tests:

x07 test --manifest tests/tests.json

Step 5: pack locally (optional sanity check)

mkdir -p dist
x07 pkg pack --package . --out dist/acme-hello-demo-0.1.0.x07pkg

Step 6: publish to the official registry

The official index URL is:

  • sparse+https://registry.x07.io/index/

6.1 Login

Prefer stdin so tokens don’t end up in shell history:

printf '%s' "$X07_TOKEN" | x07 pkg login --index sparse+https://registry.x07.io/index/ --token-stdin

6.2 Publish

x07 pkg publish --index sparse+https://registry.x07.io/index/ --package .

Step 7: consume the package (end-to-end verification)

In a fresh directory:

mkdir -p /tmp/consume-hello && cd /tmp/consume-hello
x07 init
x07 pkg add acme-hello-demo@0.1.0 --sync

Then import ext.acme_hello_demo and call ext.acme_hello_demo.hello_v1.