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

fieldmeaning
moduleThe package's identity, normally its forge path. This is what ecko get resolves.
versionSemantic version. A release workflow asserts the git tag matches it.
entrypointThe file loaded on import. Defaults to main.ecko.
descriptionOne line. It appears in generated documentation.
author, licenseMetadata.
capabilitiesWhat the package expects to need. Advisory - see below.
dependenciesWhat it imports, and what each is granted.
environmentEnvironment 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.

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.

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_MAX_DEPTH": "5000" } }

Applied before evaluation, and it overrides the surrounding shell - the opposite precedence to std.config. The reason is that this block exists so a project can pin the environment its code expects, which it cannot do if whatever happens to be exported wins. Machine-specific values belong in the shell, not here. Never put a secret in it.