The ecko.json manifest
ecko init # scaffold one
{
"module": "github.com/ecko-lang/url",
"version": "0.9.5",
"entrypoint": "main.ecko",
"description": "URL parsing, query strings, and reference resolution.",
"license": "MIT",
"capabilities": [],
"dependencies": {}
}
Fields
| field | meaning |
|---|---|
module | The package's identity, normally its forge path. This is what ecko get resolves. |
version | Semantic version. A release workflow asserts the git tag matches it. |
entrypoint | The file loaded on import. Defaults to main.ecko. |
ecko | The lowest Ecko the package works on. Checked on import. |
description | One line. It appears in generated documentation. |
author, license | Metadata. |
capabilities | What the package expects to need. Advisory - see below. |
dependencies | What it imports, and what each is granted. |
environment | Environment variables to apply before the program runs. |
Any other field is yours. The whole manifest is readable from the program as std.defaults, which is why an app manifest often carries port, db_path and similar - configuration with no parsing code. The commands that edit this file - ecko get, ecko remove - rewrite only the dependencies value and leave every other byte as you wrote it: your keys, their order, your formatting, and an explicit "capabilities": [] (which says the package is pure, so it is kept even though it is empty).
Keys must be valid identifiers, because they are read as defaults.<key>. A key with a dash is an error rather than a value you cannot reach.
ecko is the version you need
{ "module": "github.com/me/gps", "version": "1.0.0",
"entrypoint": "main.ecko", "ecko": "0.30.0" }
Someone importing this on an older build is told so:
package 'gps' needs Ecko 0.30 or newer, and this is 0.29.0.
Upgrade with `curl -fsSL https://ecko.sh/install | sh`, or pin an
earlier version of the package.
Without it the failure surfaces wherever the missing feature happens to be used - a message about a verb that does not exist, pointing nowhere near the cause.
Compared on major and minor only. A package at 0.30.4 needs the 0.30 line, not that exact patch, so a patch release of the package never demands a patch release of Ecko.
Leave it out if you do not need one. Absent means "any", which is right for most packages, and a floor set higher than the truth only turns people away who would have been fine.
capabilities is advisory
The list documents intent. What a package actually gets is the grant its importer gives it, and nothing else. A manifest asking for net in a project that grants nothing gets nothing.
Keep it honest anyway: it is what a reader checks first, and [] is a genuine claim worth making - it says this package cannot touch the network, the filesystem or the environment.
Dependencies
{
"dependencies": {
"url": "github.com/ecko-lang/url@v0.9.5",
"mysql": {
"path": "github.com/ecko-lang/mysql-client",
"version": "v0.9.5",
"grant": ["net"]
}
}
}
The short form is a string. The long form adds grant, and is also how you choose the import name: the key is what import binds. That matters when a repository name is not a valid identifier - mysql-client cannot be an Ecko identifier, so it is aliased to mysql.
Name and directory must agree
import foo reads vendor/.../foo/ecko.json and errors if the manifest disagrees with the directory it was found in. This is why a repository named for its forge slug declares the import name its users will type.
A malformed manifest is a hard error, not a silent zero-grant. Failing loudly was a deliberate change: a typo used to produce a package that mysteriously could not do anything.
environment
{ "environment": { "ECKO_AI_PROVIDER": "ollama", "ECKO_LIMIT_DEPTH": "5000" } }
Applied before evaluation, to any variable the shell has not already set - the same env-over-file precedence as std.config, so what the person running the program exported always wins. (Before 0.58 the block overrode the shell.) Never put a secret in it.
Ten ECKO_* variables are refused from a manifest - the ones that decide where data goes or what is trusted, like ECKO_AI_BASE_URL and ECKO_NET_ALLOW_HTTP. See defaults for the list and the reasoning.