Skip to main content

Working with Dependencies

NeuroScript packages can depend on other packages distributed as git repositories or local directories. The dependency system handles fetching, caching, version locking, and integration with the compiler.

Adding Dependencies

Use neuroscript add to declare a dependency in your Axon.toml:

Git Dependencies

# Add from a git repository
neuroscript add attention-blocks \
--git "https://github.com/user/attention.git"

# Pin to a specific branch
neuroscript add attention-blocks \
--git "https://github.com/user/attention.git" \
--branch main

# Pin to a tag
neuroscript add attention-blocks \
--git "https://github.com/user/attention.git" \
--tag v0.2.0

# Pin to a specific commit
neuroscript add attention-blocks \
--git "https://github.com/user/attention.git" \
--rev abc123

Path Dependencies

For local development, reference packages by filesystem path:

neuroscript add local-utils --path ../local-utils

Path dependencies are resolved relative to your project root. They are useful when developing multiple packages together.

Version Dependencies

For future registry support:

neuroscript add core-primitives --version "^1.0"

Resulting Axon.toml

After adding dependencies, your manifest will look like:

[dependencies]
attention-blocks = { git = "https://github.com/user/attention.git", branch = "main" }
local-utils = { path = "../local-utils" }
core-primitives = "^1.0"

Fetching Dependencies

Run neuroscript fetch to download all declared dependencies:

neuroscript fetch
Fetching 2 dependencies...
✓ attention-blocks -> /Users/you/.neuroscript/git/a1b2c3
✓ local-utils -> /Users/you/projects/local-utils

✓ Generated Axon.lock
✓ All dependencies fetched successfully

Use --verbose for detailed output, or --update to pull the latest compatible versions:

neuroscript fetch --verbose
neuroscript fetch --update

Where Dependencies Go

  • Git dependencies are cloned to ~/.neuroscript/git/<hash>/
  • Path dependencies are resolved in place (no copying)
  • A shared cache at ~/.neuroscript/ avoids redundant clones

The Lockfile (Axon.lock)

After fetching, an Axon.lock file is generated that pins exact versions and commit hashes:

# This file is @generated by neuroscript
# It is not intended for manual editing

version = 1

[[package]]
name = "attention-blocks"
version = "0.3.1"
source = "git+https://github.com/user/attention.git?rev=abc123"

[[package]]
name = "local-utils"
version = "0.1.0"
source = "path+/Users/you/projects/local-utils"

Commit your lockfile to version control. This ensures everyone on your team builds with the exact same dependency versions.

Using Neurons from Dependencies

Once dependencies are fetched, import their neurons using use statements in your .ns files:

Wildcard Import

Import all exported neurons from a package:

use attention-blocks,src/*

neuron MyModel(dim, heads):
in: [*batch, seq, dim]
out: [*batch, seq, dim]
graph:
in -> MultiHeadAttention(dim, heads) -> out

Specific Import

Import a single neuron by name:

use attention-blocks,src/CrossAttention

neuron DecoderBlock(dim, heads):
in: [*batch, seq, dim]
out: [*batch, seq, dim]
graph:
in -> CrossAttention(dim, heads) -> out

Multiple Imports

use attention-blocks,src/*
use local-utils,src/*

neuron FullModel(dim, heads, expansion):
in: [*batch, seq, dim]
out: [*batch, seq, dim]
graph:
in ->
MultiHeadAttention(dim, heads)
SwiGLU_FFN(dim, expansion)
out

Integration with Compile and Validate

The compiler automatically loads dependencies when an Axon.lock file is present:

# Validates with all dependency neurons available
neuroscript validate src/model.ns

# Compiles with dependency neurons in scope
neuroscript compile src/model.ns

# Skip dependency loading (useful for standalone files)
neuroscript validate src/model.ns --no-deps
neuroscript compile src/model.ns --no-deps

The compiler walks up from your input file to find the nearest Axon.lock, then loads all declared dependencies into the symbol table before validation and compilation.

Merge Precedence

When the same neuron name exists in multiple sources, precedence is:

  1. User-defined neurons (your .ns files) - highest priority
  2. Standard library neurons
  3. Dependency neurons - lowest priority

This means you can override any dependency or stdlib neuron by defining one with the same name in your project.

Discovering Available Neurons

Use the list command to explore what neurons are available:

# List all stdlib primitives and composites
neuroscript list --stdlib

# List neurons from a specific dependency
neuroscript list --package attention-blocks

# List everything: stdlib + all dependencies
neuroscript list --available

# List neurons defined in a file
neuroscript list src/model.ns

Full Workflow Example

Here's a complete example of consuming a package:

# 1. Initialize your project
neuroscript init my-model --author "You <[email protected]>"
cd my-model

# 2. Add a dependency
neuroscript add transformer-blocks \
--git "https://github.com/user/transformer-blocks.git"

# 3. Fetch it
neuroscript fetch

# 4. See what neurons are available
neuroscript list --available

5. Write your model using imported neurons in src/my_model.ns:

use transformer-blocks,src/*

neuron MyLanguageModel(dim, heads, layers, vocab):
in: [*batch, seq]
out: [*batch, seq, vocab]
graph:
in ->
Embedding(vocab, dim)
PreNormBlock(dim, heads, 4)
PreNormBlock(dim, heads, 4)
PreNormBlock(dim, heads, 4)
LayerNorm(dim)
Linear(dim, vocab)
out

6. Validate and compile:

neuroscript validate src/my_model.ns
neuroscript compile src/my_model.ns -o model.py

The compiled Python module will include all necessary imports for both your neurons and the dependency neurons used in the graph.