Reference
~1.5k tokens

Lua packages

A Lua package lets you add tools, commands, keybindings, and event handlers without copying its code into init.lua. Maki can load a package that you put on disk, or it can install one from a Git repository and lock it to one commit.

A package directory holds sorted plugin/*.lua entry files, modules at lua/<module>.lua or lua/<module>/init.lua, and a plugin.toml manifest. The entry files share one environment and use the API the plugin guide describes.

Install from Git

Declare managed packages in the global init.lua, normally ~/.config/maki/init.lua:

maki.pack.add({
  "https://github.com/example/maki-goal",
  {
    src = "https://github.com/example/maki-review",
    version = "v1.2.0",
  },
})

Each entry is a source string, or a table with src, version, name, and data. Maki derives the directory and owner name from src, and name overrides it when two sources end in the same repository name.

Maki shows all new packages in one install prompt, on the terminal, before the UI starts. It writes the selected Git commit to pack-lock.json in your config directory. Commit this file if you want another machine to install the same revisions.

Every project shares one lockfile and package directory, so a project .maki/init.lua cannot add packages. It can still read state with maki.pack.get and activate a package with maki.packadd.

Maki refuses a package name that matches a builtin plugin or a package you placed by hand, and reports the conflict at startup.

Set confirm = false only when the package source is already trusted and Maki must run without a terminal:

maki.pack.add({ "https://github.com/example/maki-goal" }, {
  confirm = false,
})

This option skips the install prompt. It does not approve package permissions. Maki rejects an HTTP source carrying a username, password, or token, since Git and the lockfile would store it. Use a credential helper or an SSH agent.

Set load = false to install a package without loading it at startup. Set load to a function when the package needs a custom entry point:

maki.pack.add({
  {
    src = "https://github.com/example/maki-review",
    data = { module = "review" },
  },
}, {
  load = function(package)
    require(package.spec.data.module).setup()
  end,
})

The function runs as the package owner. It receives the package spec and its installed path. The data field can contain any Lua value.

See maki.pack.add and maki.pack.get for the full signatures.

Pinned revisions

A lockfile entry wins over version: once Maki records a commit, it installs that commit everywhere, and a later version in init.lua changes nothing. To move a package, delete its entry from pack-lock.json and start Maki again. Maki resolves version and records the commit it picked.

A changed src makes the recorded revision meaningless, so Maki installs the new source and records it. That is also a new trust decision, so the install and permission prompts come back.

Removing a maki.pack.add entry stops the package from loading. Its lockfile entry and its checkout stay on disk until you delete them.

Package permissions

A managed package can ask for guarded APIs in plugin.toml:

[permissions]
fs_read = true
fs_write = true
net = true
run = true
env = true

The manifest states what the package wants, and Maki asks about new permissions in a separate prompt. A package with no plugin.toml asks for nothing, and every guarded call it makes fails. The permission list covers what each name gates.

An approval applies only to the same package name and source. Maki keeps approvals in <maki-data>/site/pack-approvals.json, where <maki-data> is the data directory from the directory layout. Approvals describe trust on this machine and must not be committed with pack-lock.json.

Only the interactive UI can ask. --print, SDK mode, the ACP server, and the other subcommands never prompt, so a package waiting for a decision comes back as a startup warning instead of loading.

Install by hand

Clone a package into a Neovim-style package directory:

<maki-data>/site/pack/<group>/start/<name>/
<maki-data>/site/pack/<group>/opt/<name>/

Pick any <group> name except core, which Maki reserves for its own installs and never scans.

A start package loads at startup. An opt package stays installed until something activates it.

Placing a package by hand means you trust its code the way you trust your own init.lua. Maki grants it exactly the permissions its plugin.toml requests, with no approval step.

Activate an installed package

An opt directory, or a managed package declared with load = false, starts with maki.packadd. Call it from init.lua or from another package:

maki.packadd("my-package")

Maki loads the named package after the calling Lua task returns. A package that maki.packadd activates can activate another one in turn. Maki reports a name that no installed package matches, and refuses a package that plugins.<name>.enabled = false disabled.

Managed checkouts

Maki restores a missing checkout only when the global config still declares the package and its source matches the lockfile entry. Installs and approval writes share one file lock, so two Maki processes cannot interleave them. The kernel releases that lock when the process exits, so a crash leaves nothing to clean up.

Each revision gets its own directory under <maki-data>/site/pack/core/<name>/<commit>/. At startup Maki deletes stale revisions, skipping any that a running process still holds.