Metadata-Version: 2.3
Name: jj-core
Version: 0.1.0
Summary: Extensible core runtime and CLI for Johnny-Johnny.
Keywords: cli,plugins,developer-tools,automation
Author: Grant Gortsema
Author-email: Grant Gortsema <grant.gortsema@gmail.com>
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development
Classifier: Topic :: System :: Systems Administration
Requires-Dist: packaging>=24,<26
Requires-Dist: rich>=13.9,<16
Requires-Dist: typer>=0.16,<1
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/ggortsema/jj-core
Project-URL: Repository, https://github.com/ggortsema/jj-core
Project-URL: Issues, https://github.com/ggortsema/jj-core/issues
Description-Content-Type: text/markdown

# jj-core

`jj-core` is the lightweight, extensible runtime for Johnny-Johnny. Core owns
the global `jj` command, plugin discovery, local plugin state, and plugin
package reconciliation. Useful capabilities live in separate Git repositories.

The historical `johnny-johnny-agent` application remains intact. This is a new,
clean platform core that borrows only proven CLI and engineering conventions.

## Normal installation

`jj-core` is the only project in the MVP published to PyPI. A user with `uv`
installs it with:

```bash
uv tool install jj-core
jj --help
```

A clean installation exposes only the core namespace:

```text
Commands:
  plugin  Install, inspect, and remove JJ plugins.
```

## Installing plugins

Plugins are **not** published to PyPI. They are ordinary Python projects in Git
repositories and follow the conventions documented below.

### Friendly names in the core catalog

`jj-core` packages a catalog that maps a friendly name to a repository:

```toml
[plugins."hello-world"]
repository = "https://github.com/ggortsema/jj-hello-world.git"
```

A user installs the reference plugin with:

```bash
jj plugin install hello-world
```

### Any additional repository

A plugin not listed in the catalog can be installed directly from its Git
repository:

```bash
jj plugin install https://github.com/example/jj-example.git
```

Private repositories work when the user's normal Git credentials can clone the
repository, for example:

```bash
jj plugin install git+ssh://git@github.com/company/jj-forge-misc.git
```

### Local plugin development

A local project directory is installed editable:

```bash
jj plugin install ../jj-hello-world
```

Source remains in that directory, and changes are visible to the JJ runtime
without rebuilding the plugin package.

## Installation-aware help

Enabled plugins are loaded before Typer renders help. After installing the
reference plugin:

```bash
jj --help
```

includes:

```text
Commands:
  plugin
  hello-world
```

The plugin owns its namespace and commands:

```bash
jj hello-world --help
jj hello-world say-hello Grant
```

Output:

```text
Hello, Grant!
```

## Plugin management

```bash
jj plugin catalog
jj plugin install <name-local-path-or-repository>
jj plugin list
jj plugin remove <name>
```

Desired plugin state is persisted at:

```text
~/.config/jj/plugins.toml
```

When a plugin is added or removed, JJ asks `uv` to recreate the isolated tool
environment as:

```text
jj-core + every configured enabled plugin
```

This uses supported `uv tool install --with` / `--with-editable` composition.
JJ does not mutate uv's tool environment with `pip`.

Remote Git installs are pinned to the exact commit inspected during
installation. Rebuilding the runtime therefore does not silently move a plugin
to a newer commit.

## Plugin convention

Every plugin repository must contain these at its root:

```text
jj-plugin.toml
pyproject.toml
src/
```

The descriptor is declarative and contains identity and compatibility metadata:

```toml
schema_version = 1

[plugin]
name = "hello-world"
distribution = "jj-hello-world"
version = "0.1.0"
namespace = "hello-world"
description = "Reference plugin demonstrating JJ CLI extension."

[compatibility]
jj_core = ">=0.1,<1"
```

The Python project declares a matching entry point:

```toml
[project.entry-points."jj.plugins"]
hello-world = "jj_hello_world.plugin:plugin"
```

The entry point resolves to a `jj_core.plugin_api.CliPlugin`. The plugin owns
its Typer app, help text, namespace, arguments, options, services, and tests.
Core owns discovery and composition.

## Resolution behavior

```text
jj plugin install hello-world
  -> core catalog
  -> Git repository
  -> shallow checkout
  -> root jj-plugin.toml
  -> metadata and compatibility validation
  -> exact Git commit pin
  -> uv tool environment reconciliation
  -> fresh-process entry-point verification
  -> atomic local configuration write
```

A repository supplied directly begins at the Git-repository step. A local path
uses the same descriptor and entry-point conventions but is installed editable.

A configured plugin that is missing or cannot load produces a warning; healthy
core commands and other plugins continue to work.

## Requirements

For core installation and package reconciliation:

- `uv`

For plugin installation from a repository:

- Git
- access to the repository through the user's existing Git authentication

`uv` can obtain a compatible Python automatically.

## Local development

Place the projects beside each other:

```text
johnny-johnny/
├── jj-core/
└── jj-hello-world/
```

Then:

```bash
cd jj-core
uv sync
uv run pytest -m "not integration"
uv tool install -e .

jj plugin install ../jj-hello-world
jj --help
jj hello-world say-hello Grant
jj plugin list
jj plugin remove hello-world
```

Run the full isolated uv/Git lifecycle test with:

```bash
uv run pytest -m integration
```

## Configuration overrides

Primarily for tests and advanced installations:

- `JJ_CONFIG_HOME`
- `JJ_PLUGIN_CATALOG`
- `JJ_UV_EXECUTABLE`
- `JJ_CORE_INSTALL_SOURCE`
- `JJ_CORE_INSTALL_EDITABLE`
- `JJ_PYTHON`
- uv's `UV_TOOL_DIR` and `UV_TOOL_BIN_DIR`

## Publishing core

The repository includes a tag-triggered GitHub Actions release workflow for
publishing **only `jj-core`** to PyPI through Trusted Publishing.

See [`docs/publishing.md`](docs/publishing.md) and the formal [`MVP acceptance criteria`](docs/architecture/mvp-acceptance.md).
