Thank you for your interest in contributing to Duso! This document explains how the project is organized and where to make different types of changes.
We welcome your contributions! Before you open a PR, please:
Duso is organized around two core audiences: Go developers embedding Duso and script writers using the CLI.
cmd/duso/ - CLI application (entry point)
pkg/
├── script/ - Core language (lexer, parser, resolver, evaluator)
├── runtime/ - Every builtin, plus HTTP, datastore, websockets, SQL
├── cli/ - CLI-only builtins (file I/O, require, sys) and module resolution
├── core/ - Small shared helpers
├── lsp/ - Language server (completion, diagnostics, hover)
└── version/ - Version constants
stdlib/ - Duso-source standard library (.du modules, embedded)
contrib/ - Duso-source community modules (.du, embedded)
examples/ - Duso example scripts (embedded)
go-embedding/ - Go embedding examples (not embedded in binary)
docs/
├── reference/ - Per-symbol reference docs
├── ideas/ - Proposed, not-yet-built designs
└── cli/ - CLI help text
Everything under docs/, stdlib/, contrib/ and examples/ is copied into the binary
by go generate ./cmd/duso and served from /EMBED/. That embed is deliberate: a duso
binary carries the docs and libraries for exactly its own revision, so a user always reads
documentation that matches the code they are running. Keep it curated — anything stale in
docs/ at release time is frozen into that release.
Three-Layer Architecture:
pkg/script/ - Language Core (Embeddable)
pkg/runtime/ - Builtins and Orchestration (Embeddable)
pkg/runtime/builtin_*.go files, registered in pkg/runtime/register.goHTTPServerValue) and client (used by fetch())DatastoreValue) and replicationpkg/cli/ - CLI Features (CLI-only)
builtin_*.go: load, require, sys, watch, consolepkg/cli/module_resolver.go)pkg/cli/vfs.go)pkg/cli/register.go)Note that builtins live in pkg/runtime, not pkg/script. pkg/script is the bare
language; embedding it alone gives you a sandbox with no print().
You want to add: Operators, syntax, control flow, new built-in functions
Files to modify:
pkg/script/token.go - Add token type if neededpkg/script/lexer.go - Add tokenization if neededpkg/script/parser.go - Add parsing logicpkg/script/evaluator.go - Add evaluation logicpkg/runtime/builtin_*.go - If it’s a built-in functiondocs/learning-duso.md - Document the featuredocs/duso-primer.md - Add a terse line if it changes how correct code is writtenexamples/ - Add an example demonstrating the featureProcess:
pkg/script/examples/docs/learning-duso.mdduso lint over any doc you touched — code blocks in .md are lintedYou want to add: HTTP server enhancements, datastore features, concurrency primitives, goroutine management
Files to modify:
pkg/runtime/builtin_<name>.go - Implement the builtinpkg/runtime/register.go - Register itdocs/reference/<name>.md - Per-symbol documentationdocs/internals.md - Only if it changes the architectureexamples/ - Add an exampleProcess:
pkg/runtime/builtin_<name>.gopkg/runtime/register.go — runtime builtins register themselves there;
they do not need a pkg/cli wrapperdocs/reference/<name>.mdExamples of runtime features:
pkg/runtime/builtin_http_server.go + pkg/runtime/http_server.gopkg/runtime/builtin_datastore.go + pkg/runtime/datastore.gopkg/runtime/goroutine_context.go for context carried across spawn()/run()You want to add: File I/O enhancements, module resolution improvements, new CLI subcommands
Files to modify:
pkg/cli/builtin_<name>.go - Implement the featurepkg/cli/register.go - Register itcmd/duso/main.go - Only for a new subcommanddocs/reference/<name>.md - Document the builtinProcess:
pkg/cli/pkg/cli/register.goexamples/pkg/runtime)Examples of CLI-only features:
load, save, include)require)env)You want embedders to: Use a pre-built function in their apps
Files to modify:
pkg/runtime/builtin_*.go - Add the functionpkg/runtime/register.go - Register itdocs/reference/<name>.md - Document itdocs/learning-duso.md - If it’s a core built-inProcess:
pkg/runtime/builtin_*.goYou want to: Share a Duso module that gets included in Duso binary distributions
What you provide: Pure Duso code - no Go required
Files to modify:
duso-<modulename> on GitHub.du files with Apache 2.0 licenseProcess:
Create your module in a separate repository
duso-postgres, duso-helpers, etc.Open an issue on the Duso repository requesting review
Once approved, module is added to contrib/
Your module is frozen in time with each release
For more details: See contrib/README.md
Context: See custom distributions to understand how modules are included in binary distributions.
Each doc has one job. Put a change where it belongs rather than where it is easiest to add.
Reference — the authority on behavior
docs/reference/<name>.md - One file per builtin, keyword and symbol. Every builtin has
one, and it is what duso doc TERM prints. Parameters, return values, errors, examples.docs/formal-language-spec.md - Grammar and semantics, precisely statedLearning — prose for people
docs/learning-duso.md - Language syntax and semantics, explained at lengthdocs/duso-style-guide.md - How idiomatic duso is writtendocs/debugging-scripts.md, docs/files-and-modules.md,
docs/virtual-filesystem.md, docs/bundling-applications.md - Topic guidesPrimers — condensed, LLM-optimized
docs/duso-primer.md - The language, dense. Notes here are one line, never a
subsection with examples; depth belongs in a topic guide or the referencedocs/datastore-primer.md - datastore() in fulldocs/http-primer.md - http_server(), fetch(), websocket()Contributor-facing
docs/internals.md - Architecture, the evaluation pipeline, the Go embedding APIdocs/ideas/ - Proposed designs that are not built. Say so at the top of the file.
Delete the doc when the feature ships or the design is abandoneddocs/performance-report.md, docs/datastore-1.7-performance.md,
docs/todo-comparison.md - Measurements and comparisonsOther
docs/index.md - Table of contents. A new doc that is not listed here is invisibledocs/cli/help.md - Text printed by duso helpdocs/installing.md, README.md - Front doorProcess:
duso lint <file>.md — code blocks inside Markdown are linted, so broken examples
are caught before they shipdocs/index.mdRemember the embed. docs/ is copied into the binary, so a doc that is wrong at
release time is frozen into that release and cannot be patched afterward. Prefer deleting
a stale doc over leaving it to mislead.
Process:
camelCase for functions/variablessnake_case for Duso language functions/examples/ for user-facing featuresdocs/reference/<name>.mdfeature/add-xyz, fix/issue-123Label: feature: language
These go in pkg/script/ and may affect both embedding and CLI.
Example: “Add switch/case syntax”
Label: feature: runtime
These go in pkg/runtime/ and can be used in embedded and CLI contexts.
Example: “Add request caching to fetch()“, “Add timeout to datastore operations”
Label: feature: cli
These go in pkg/cli/ and only affect CLI usage.
Example: “Add ability to set environment variables from script”, “Improve module resolution for monorepos”
Label: docs
Unclear, missing, or outdated documentation.
Example: “The file I/O guide doesn’t explain path resolution”
Label: bug
Something doesn’t work as documented.
Provide:
git clone https://github.com/duso-org/duso
cd duso
# For maintainers only: install git hooks for automatic versioning
./git-setup.sh
# Build the CLI
./build.sh
# Run a test script
duso examples/http/minimal.du
For maintainers: After cloning, run ./git-setup.sh to install git hooks for automatic versioning based on commit messages (feat:, fix:, major: prefixes).
Symlink for convenience (so you can run duso from anywhere):
ln -s $(pwd)/bin/duso /usr/local/bin/duso
# Run tests
go test ./...
# Run a specific example
duso examples/http/minimal.du
# Static analysis (works on .du files and on code blocks in .md files)
duso lint examples/http/minimal.du
# Step through a script in the debugger
duso debug examples/debug/basic.du
# Test a Go embedding example
cd go-embedding
go run ./hello-world
pkg/script/ focused on languageBe respectful, inclusive, and constructive. Welcome contributors and help them succeed.
Thank you for contributing to Duso!