Skip to main content
Sifr packages let you organize, share, and reuse code across projects. Every Sifr package is backed by Cargo, the Rust package manager, which handles distribution, dependency resolution, lockfiles, and registries. Sifr then layers its own concerns on top: compiler semantics, source layout, edition, and the public API surface declared in your .sifr files. Understanding where each tool’s responsibility begins and ends will save you a lot of time as your project grows.

Package layouts

Sifr supports two production layouts depending on whether you are building a reusable library or a runnable application.

Library layout

A library package exposes a public API that other packages can import. The minimum required files are:
sifr-http/
  Cargo.toml
  Cargo.lock
  sifr.toml
  src/
    __init__.sifr
    client.sifr
    lib.rs
src/__init__.sifr is the public API entry point. Any name you define or re-export there becomes available to packages that depend on sifr-http.

App layout

An app package produces one or more runnable binaries. The default entry point is src/main.sifr, and additional targets are discovered automatically from src/bin/*.sifr.
sifr-app/
  Cargo.toml
  Cargo.lock
  sifr.toml
  src/
    main.sifr
    bin/
      admin.sifr
    lib.rs

How sifr.toml and Cargo.toml divide responsibilities

Both manifests live at the project root and are always required for a production package. They do not overlap.
ConcernOwned by
Package name, edition, compiler version, source rootsifr.toml
Sifr scripts, privacy settings, native trust policysifr.toml
Distribution metadata, registry, publishing credentialsCargo.toml
Dependency resolution, lockfiles, Git/path sources, workspacesCargo.toml
include/exclude archive rulesCargo.toml
Cargo package names generated by sifr init follow the sifr-<kebab-case-name> convention. The sifr.toml name uses the plain package name (for example, demo_json) while the Cargo package name would be sifr-demo-json.

Manifest-less mode

You do not need a package at all for quick experiments or standalone scripts. When no sifr.toml exists in the current directory or any of its parents, Sifr runs in manifest-less mode. The file’s parent directory becomes the source root and no dependency graph is loaded.
sifr run path/to/file.sifr
sifr check path/to/file.sifr
sifr emit path/to/file.sifr
Manifest-less mode is ideal for learning and one-off scripts. Switch to a full project with sifr init as soon as you need dependencies or want to share code.
When you run these commands inside a package directory, the explicit .sifr file must reside under the package source root (usually src/). Sifr rejects files outside the source root to avoid ambiguous package membership.

Creating a new package with sifr init

sifr init scaffolds a complete, canonical package for you — including both sifr.toml and the correctly configured Cargo.toml.
1

Create a library package

Run sifr init --lib with your package name:
sifr init --lib demo_json --name demo_json
This generates:
demo_json/
  Cargo.toml
  sifr.toml
  src/
    __init__.sifr
    lib.rs
2

Create an app package

Use --bin instead to scaffold an application:
sifr init --bin demo_app --name demo_app
The generated layout uses src/main.sifr in place of src/__init__.sifr.
3

Fetch dependencies

Move into your new package directory and fetch its initial dependency set:
cd demo_json
sifr fetch
The generated Cargo.toml includes the metadata pointer that Sifr uses to locate your manifest at runtime:
# sifr-managed
[package.metadata.sifr]
manifest = "sifr.toml"
# end sifr-managed
Do not remove the # sifr-managed markers. Sifr uses them to identify and update its managed entries in Cargo.toml.

How commands use your package context

Every package-aware command resolves your project context once at startup — finding the workspace root, your sifr.toml, and the source root — and keeps that context stable for the lifetime of the command. The active lock mode you pass (--locked, --offline, or --frozen) applies automatically to all underlying operations, including dependency fetches and tree inspection. You do not need to pass lock flags separately for each step. This means that when you run sifr fetch --locked, sifr tree, or sifr check, Sifr forwards your lock and network settings consistently throughout the command without extra configuration.