No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-07 01:02:24 +00:00
src Bump jea version 2026-09-06 14:56:28 -05:00
tests Bump jea version 2026-09-06 14:56:28 -05:00
.gitignore Initial jea setup 2026-09-06 11:32:10 -05:00
Cargo.lock Bump jea version 2026-09-06 14:56:28 -05:00
Cargo.toml Bump jea version 2026-09-06 14:56:28 -05:00
README.md Add README 2026-09-06 11:48:16 -05:00

jea

jea is a small, opinionated wrapper around Jujutsu (jj) and Forgejo's tea CLI.

I like jj. I like Forgejo. I do not like remembering a pile of Git / jj git / tea commands just to move work around.

So jea gives the workflows I actually use short, predictable names.

It is built with walts-cli.

Requirements

jea expects these commands to be available in PATH:

jj
tea

walts-cli checks for them before dispatching commands.

tea must also have a configured Forgejo login with the permissions needed for the operation you are running.

Basic usage

jea <command> [args] [options]

Show available commands:

jea --help

Show command-specific help:

jea publish --help

Everyday jj wrappers

Status

jea status
jea st

Runs jj st.

New change

jea new
jea n

Create a new change with a description:

jea new -m "Implement the thing"
jea new --message="Implement the thing"

Edit a change

jea edit <change>
jea e <change>

Example:

jea e xowwnkro

Squash

jea squash

Split

jea split

Resolve

jea resolve

Fetch

jea fetch

Runs jj git fetch.

Push

jea push

Runs jj git push.

Repository setup

Initialize

jea init

init bootstraps a jj repository and its main bookmark.

A Forgejo repository can also be supplied:

jea init -r jea
jea init --repo=jea

When a repository is supplied, jea also adds the Forgejo remote before bootstrapping main.

jea is currently opinionated around my Forgejo setup, including the bedrawk.net SSH host and walt owner.

Remotes

The remote> commands wrap jj git remote.

Because > is shell redirection syntax, quote these command names in shells that interpret it.

Add my Forgejo origin

jea 'remote>forgejo' jea

This currently builds:

ssh://[email protected]/walt/jea.git

and adds it as origin.

Add a remote

jea 'remote>add' origin ssh://[email protected]/user/repo.git

List remotes

jea 'remote>list'

Remove a remote

jea 'remote>remove' origin

Rename a remote

jea 'remote>rename' origin upstream

Change a remote URL

jea 'remote>set-url' origin ssh://[email protected]/user/repo.git

Forgejo repositories and issues

List repositories

jea repos

Create a repository

jea 'create>repo' my-project

Useful options:

jea 'create>repo' my-project --private
jea 'create>repo' my-project --init
jea 'create>repo' my-project -O walt
jea 'create>repo' my-project -d "Some repo"

Supported options:

-O, --owner         repository owner
-d, --description   repository description
-p, --private       make repository private
-i, --init          initialize the repository

Create an issue

jea 'create>issue' "Parser bug"

With a description:

jea 'create>issue' "Parser bug" -d "Something exploded"

Target a specific repository:

jea 'create>issue' "Parser bug" -r walt/jea

Add labels:

jea 'create>issue' "Parser bug" -L bug,parser

Supported options:

-d, --description   issue description
-L, --labels        comma-separated labels
-r, --repo          repository slug or path

If the current repository has a Forgejo remote that tea can identify, --repo is usually unnecessary.

Workflow commands

This is where jea becomes more than a pile of aliases.

Sync

jea sync

The default workflow is:

jj git fetch
jj rebase -d trunk@origin

Override the destination:

jea sync -t main@origin
jea sync --target=main@origin

Publish

Publish the current jj change as a Forgejo pull request:

jea publish <bookmark>

Example:

jea publish jea-workflows

With a title and base:

jea publish jea-workflows \
  -t "Add sync, publish, create, and remote workflows" \
  -b main

publish currently does:

jj bookmark set <bookmark> -r @
jj git push --bookmark <bookmark>
tea pr create --head <bookmark> --base <base> --title <title>

The default base is trunk.

If no title is provided, the bookmark name is used.

Approve a pull request

jea approve <pr>

Example:

jea approve 4

Forgejo may reject approval of your own pull request, which is expected server-side behavior.

Merge a pull request

jea merge <pr>

Example:

jea merge 5

After merging, jea automatically fetches the updated remote state with jj.

The default merge style is merge.

Override it with:

jea merge 5 -s squash
jea merge 5 --style=rebase

Supported styles are those provided by tea:

merge
rebase
squash
rebase-merge

Example workflow

A normal feature flow can look like:

jea new -m "Add cool feature"

# hack hack hack

jea st

jea publish cool-feature \
  -t "Add cool feature" \
  -b main

After review / CI:

jea merge <pr-number>

Then start the next change:

jea new -m "Next thing"

For someone else's PR:

jea approve <pr-number>
jea merge <pr-number>

Why create>repo instead of subcommands?

jea intentionally treats hierarchy as naming, not parser architecture.

These are flat command names:

create>repo
create>issue
remote>add
remote>list
remote>remove

That keeps the CLI parser simple while still visually grouping related operations.

Testing

Run the full test suite:

cargo test

The tests focus on the CLI contract without actually creating repositories, opening PRs, rebasing history, or calling Forgejo.

The project has dedicated coverage for:

basic CLI behavior
wrapper commands
repository / issue creation
remote commands
sync workflows
publish workflows
PR approve / merge parsing

Real jj / tea behavior is smoke-tested manually against Forgejo.

Status

jea is intentionally small and personal.

The goal is not to replace every jj or tea command. Raw jj and tea remain available for advanced work.

jea exists to make the common path pleasant.