Gitea CLI

Gitea CLI patterns for self-hosted Git workflows.

tea CLI — Authentication

Login to your Gitea instance
tea login add --name domus --url https://git.domusdigitalis.dev --token <your-token>
List configured logins
tea login list
Set default login
tea login default domus

tea CLI — Repositories

Create a repo
tea repo create --name domus-api --private
List your repos
tea repo list
Clone a repo
git clone git@git.domusdigitalis.dev:evan/domus-api.git

tea CLI — Issues & PRs

Create an issue
tea issue create --title "Add Ollama RAG endpoint" --body "Phase 3 of domus-api roadmap"
List issues
tea issue list
Create a pull request
tea pr create --title "feat: multi-spoke support" --base main --head feature-branch
List PRs
tea pr list

Gitea REST API — Direct Access with curl

Gitea has a Swagger-documented REST API. No special CLI needed — just curl + jq.

Set your token as a variable
export GITEA_TOKEN="your-api-token"
export GITEA_URL="https://git.domusdigitalis.dev/api/v1"
List your repos
curl -s -H "Authorization: token $GITEA_TOKEN" "$GITEA_URL/user/repos" | jq -r '.[] | "\(.name)\t\(.size) KB"' | sort
Create a repo
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"association-engine","private":true}' \
  "$GITEA_URL/user/repos" | jq '{name, clone_url: .ssh_url}'
Get repo details
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/repos/evan/domus-api" | jq '{name, size, created_at, updated_at}'
List repo contents (directory listing)
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/repos/evan/domus-api/contents/src/domus_api" | jq -r '.[] | "\(.type)\t\(.size)\t\(.name)"'
Read a file (base64 decode)
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/repos/evan/domus-api/contents/pyproject.toml" | jq -r '.content' | base64 -d
List commits
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/repos/evan/domus-api/commits?limit=10" | jq -r '.[] | "\(.commit.author.date[:10])\t\(.commit.message | split("\n")[0])"'
Create an issue via API
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Phase 3: Ollama RAG","body":"Architecture documented in roadmap partial"}' \
  "$GITEA_URL/repos/evan/domus-api/issues" | jq '{number, title, state}'
List issues
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/repos/evan/domus-api/issues" | jq '[.[] | {number, title, state}]'

Gitea + jq Patterns

All repos sorted by last update
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/user/repos?limit=50" | jq -r '.[] | "\(.updated_at[:10])\t\(.name)"' | sort -r
Find repos by language
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/user/repos?limit=50" | jq -r '.[] | "\(.language // "none")\t\(.name)"' | sort
Repo sizes ranked
curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/user/repos?limit=50" | jq -r '.[] | "\(.size)\t\(.name)"' | sort -rn

Why Three Forges?

Forge Purpose When It Matters

GitHub

Primary — PRs, community, CI, portfolio visibility

Always. This is where people see your work.

GitLab

Work backup — CHLA CI/CD, enterprise features

When work requires GitLab. Backup for everything.

Gitea

Sovereignty — self-hosted at git.domusdigitalis.dev

When GitHub/GitLab go down. When you want full control. When privacy matters.

The data is the same. The remotes are different interfaces to the same truth. See Multi-Remote Workflow for configuring all three.

See Also