> For the complete documentation index, see [llms.txt](https://docs.talus.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.talus.network/guides/tap-development/scaffold-and-package.md).

# Scaffold the Talus Agent Package

{% hint style="info" %}
**Audience:** Nexus adopters and integrators.

**Goal:** Produce a Talus Agent Package (TAP) scaffold and identify the operator-supplied, deployment-matched Nexus dependency bundle required before validation can pass.
{% endhint %}

This page generates the on-disk shape of a Talus Agent Package (TAP) skill and replaces the scaffolded Move stub with a real state module that holds a SUI treasury and the per-vertex witness object the on-chain Tool will be registered against.

### 1. Generate the scaffold

Pick a working directory and run:

```bash
nexus tap scaffold --name "tutorial transfer" --target .
cd tutorial-transfer
```

The released scaffold writes four files under `tutorial-transfer/`:

```
tutorial-transfer/
├── dag.json                      # workflow definition (we'll edit later)
├── skill.tap.json                # skill config (we'll edit later)
└── tap/
    ├── Move.toml                 # the TAP Move package manifest
    └── sources/
        └── tutorial_transfer.move
```

The scaffolded `tutorial_transfer.move` is a single drop witness with an `init_for_test` helper — enough to compile, but nothing the workflow can actually call. This release scaffold does not create a Nexus-calling test. Add the explicit local test arrangement described in [Build the TAP Move package](/guides/tap-development/build-tap-move-package.md) before using the released published-bytecode harness.

#### Scaffold boundary

`nexus tap scaffold` creates the TAP package contract: edition `2024`, the required TAP version/environments shape, and no `[addresses]` section. The TAP validator rejects an `[addresses]` section.

This is not the same workflow as `nexus tool new --template move`, which creates a general Move Tool scaffold with `version = "1.0.0"`, edition `2024.alpha`, MVR dependencies, and no `[addresses]` table; its default Standard ABI differs from the TAP module contract. Do not copy either template wholesale into the other. Use [Build an On-Chain Tool](/guides/tool-development/build-onchain-tool.md) for the general Tool path and the [TAP CLI reference](/reference/cli/tap.md) for TAP commands.

#### 2. Review `tap/Move.toml` and update the Nexus dependencies

The scaffold ships with the six packages used by the complete TAP surface: `nexus_primitives`, `nexus_interface`, `nexus_tool`, `nexus_registry`, `nexus_workflow`, and `nexus_scheduler`. This tutorial directly uses the first two, while the remaining entries keep the package ready for registry, workflow, and Task composition. Remove a dependency only after the Move build proves it is unused.

```toml
[dependencies]
nexus_primitives = { r.mvr = "@talus/nexus-primitives" }
nexus_interface  = { r.mvr = "@talus/nexus-interface" }
nexus_tool       = { r.mvr = "@talus/nexus-tool" }
nexus_registry   = { r.mvr = "@talus/nexus-registry" }
nexus_workflow   = { r.mvr = "@talus/nexus-workflow" }
nexus_scheduler  = { r.mvr = "@talus/nexus-scheduler" }
```

The scaffold command does not fetch or stage these dependencies. The six public installation records are [nexus-primitives](https://www.moveregistry.com/package/@talus/nexus-primitives), [nexus-interface](https://www.moveregistry.com/package/@talus/nexus-interface), [nexus-tool](https://www.moveregistry.com/package/@talus/nexus-tool), [nexus-registry](https://www.moveregistry.com/package/@talus/nexus-registry), [nexus-workflow](https://www.moveregistry.com/package/@talus/nexus-workflow), and [nexus-scheduler](https://www.moveregistry.com/package/@talus/nexus-scheduler). Commit `Move.lock` and match its resolved addresses to the selected network. For offline interface/ABI inspection, use the public [Nexus Move Packages](https://github.com/Talus-Network/nexus-move-packages) source and keep its six direct package directories together with the transitive `packages/kernel` closure when required. Those copied packages contain native declarations and must not be published or treated as executable mocks; kernel is supporting closure rather than a direct application dependency, and neither policy nor kernel has a reviewed MVR package record.

The scaffold writes an `[environments]` table pre-filled with the public-testnet chain id, which is what this guide targets:

```toml
[environments]
testnet = "4c78adac"
```

Leave that as-is unless you're publishing to a different network. If you are, replace the row with `<env_alias> = "<chain-id>"` for your target network (the alias must match a name in `sui client envs`, and the chain id is what `sui client chain-identifier` prints while that env is active).

The end result looks like:

```toml
[package]
name = "tutorial_transfer"
version = "1.0.0"
edition = "2024"

[dependencies]
nexus_primitives = { r.mvr = "@talus/nexus-primitives" }
nexus_interface  = { r.mvr = "@talus/nexus-interface" }
nexus_tool       = { r.mvr = "@talus/nexus-tool" }
nexus_registry   = { r.mvr = "@talus/nexus-registry" }
nexus_workflow   = { r.mvr = "@talus/nexus-workflow" }
nexus_scheduler  = { r.mvr = "@talus/nexus-scheduler" }

[environments]
testnet = "4c78adac"
```

{% hint style="info" %}
`nexus tap validate-skill` enforces the new-style 2024 layout: the manifest must have `[package].version`, `edition = "2024"`, an `[environments]` table, and **no** `[addresses]` section. Old-style packages cannot resolve their dependency graph against the new-style published Nexus packages, so the validator rejects them up front with a pointer at the field that needs fixing.
{% endhint %}

#### 3. Replace the scaffold's Move source

The interesting work is in `tap/sources/tutorial_transfer.move`. Replace its contents with the module below. The state object holds a SUI treasury that the vertex Tool drains on each execution, plus the per-vertex witness whose UID feeds `nexus tool register onchain --tool-witness-id` and satisfies the runtime `UIDRequirements` value.

```move
module tutorial_transfer::tutorial_transfer;

use nexus_primitives::proof_of_uid::UIDRequirements;
use std::ascii::String as AsciiString;
use sui::coin::{Self, Coin};
use sui::sui::SUI;
use sui::transfer::public_share_object;

/// One-time witness — guarantees `init` runs exactly once at publish.
public struct TUTORIAL_TRANSFER has drop {}

/// Per-vertex witness. Its UID becomes the on-chain Tool's `tool_witness_id`
/// and satisfies the Tool's runtime requirements.
public struct TransferVertexWitness has key, store {
    id: UID,
}

/// Shared state for the tutorial skill. Holds the SUI treasury that the
/// transfer vertex drains on each execution plus the per-vertex witness
/// the on-chain Tool registers against.
public struct TutorialState has key, store {
    id: UID,
    transfer_vertex_witness: TransferVertexWitness,
    treasury: option::Option<Coin<SUI>>,
}

fun init(_otw: TUTORIAL_TRANSFER, ctx: &mut TxContext) {
    public_share_object(TutorialState {
        id: object::new(ctx),
        transfer_vertex_witness: TransferVertexWitness { id: object::new(ctx) },
        treasury: option::none(),
    });
}

/// Canonical FQN for the on-chain transfer vertex tool. The DAG references
/// this FQN, the tool registration uses this FQN, and the vertex module
/// returns this FQN from its own `fqn()` helper.
public fun transfer_vertex_fqn(): AsciiString {
    b"tutorial.local.transfer_vertex@1".to_ascii_string()
}

/// The id passed to `nexus tool register onchain --tool-witness-id`.
public fun transfer_vertex_tool_witness_id(state: &TutorialState): ID {
    object::uid_to_inner(&state.transfer_vertex_witness.id)
}

/// Satisfy the witness requirement carried into the on-chain Tool call.
public(package) fun satisfy_transfer_vertex_requirement(
    state: &TutorialState,
    requirements: &mut UIDRequirements,
) {
    requirements.satisfy(&state.transfer_vertex_witness.id);
}

/// Top up the treasury that future skill executions will drain.
public fun fund_treasury(state: &mut TutorialState, coin: Coin<SUI>) {
    if (state.treasury.is_some()) {
        let mut existing = option::extract(&mut state.treasury);
        coin::join(&mut existing, coin);
        option::fill(&mut state.treasury, existing);
    } else {
        option::fill(&mut state.treasury, coin);
    }
}

/// Drain the treasury. `public(package)` keeps the function callable only
/// from sibling modules in `tutorial_transfer` (i.e. `transfer_vertex`), so
/// nothing outside this package can pull funds out directly.
public(package) fun take_treasury(state: &mut TutorialState): Coin<SUI> {
    option::extract(&mut state.treasury)
}
```

Key things to notice:

* `TutorialState` is shared (`public_share_object`) so the workflow and the treasury funder can both reach it.
* `TransferVertexWitness` is stored inside `TutorialState` so its `UID` is stable for the package's lifetime — the on-chain Tool registers against it once and satisfies it on every successful call.
* `take_treasury` is `public(package)`. The sibling `transfer_vertex` module (next page) is the only caller; nothing outside the `tutorial_transfer` package can extract the coin directly.

The release scaffold has no Nexus-calling test module. Add the explicit `move-tests-published/` arrangement described in [Build the TAP Move package](/guides/tap-development/build-tap-move-package.md) when you need a local published-bytecode check; keep those tests outside the release TAP package so the release scaffold and its `sui move test` boundary remain unchanged.

#### 4. Validate locally

Run the local metadata validator before going anywhere near the chain:

```bash
nexus tap validate-skill --config skill.tap.json
```

The validator resolves `dag_path` relative to `--config` and resolves the Move package at the sibling `tap/` directory. It checks the config, DAG JSON, manifest, and source layout; it does not compile Move code. You should see:

```
[✓] Validating TAP package skill config...
```

Build and test the package separately from the directory that actually contains `Move.toml`:

```bash
cd tap
export SUI_BUILD_ENV="testnet"
sui move build --build-env "$SUI_BUILD_ENV"
cd ..
```

The metadata validator and Move build are local, so iterations are fast. The plain `sui move test` command here is limited to Nexus-free tests in the release package; it does not execute published Nexus functions. Follow [Build the TAP Move package](/guides/tap-development/build-tap-move-package.md) to add the explicit released published-bytecode test arrangement before publication.

#### What you have now

* A `tap/Move.toml` and `tap/sources/tutorial_transfer.move` that compile against the published Nexus deps for your network.
* A `TutorialState` shared object with a SUI-coin treasury, a witness object, and a `fund_treasury` entry function.
* A `skill.tap.json` and `dag.json` still in their scaffold-default shapes — we'll edit those two pages from now.

Next: [Write the on-chain transfer tool](/guides/tap-development/onchain-transfer-tool.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.talus.network/guides/tap-development/scaffold-and-package.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
