INFRASTRUCTURE AS CODE • OPEN SOURCE

Tidy Your Org Up.

The config-driven control plane for GitHub organizations. Describe repositories, teams, and branch protections in YAML; reconcile with Terraform. Every change is an audited pull request.

Terraform ≥ 1.5 integrations/github ~> 6.0 Multi-arch GHCR & Docker Hub
docker compose run --rm engine plan
$docker compose run --rm engine plan
# Reading Payment-Org-AI configuration from config/*.yml...
~ github_repository.repos["payment-service"]
  ~ description = "Payment gateway integration pipeline"
~ github_branch_protection.prot["payment-service:main"]
  + required_approving_review_count = 2
  + require_code_owner_reviews = true
----------------------------------------------------
Plan: 0 to add, 2 to change, 0 to destroy.
# Reconciled one-way: UI clickops drift back automatically.
Reconciliation Engine Terraform 1.5+ One-Way
Review Enforcement CODEOWNERS & Branch Rules
Web Dashboard Role PR Proposer (No Direct Apply)
Authentication GitHub Apps (No PATs)

THE PROBLEM

Why managing GitHub through the UI fails as your team grows.

When teams expand, clicking through repository settings tabs creates invisible security vulnerabilities, unrecorded changes, and accidental privilege escalations.

01 / DRIFT & DISARRAY

Silent Configuration Drift

Someone disables branch protection temporarily to push a quick hotfix, but forgets to re-enable it. Two months later, main has had zero review requirements without anyone knowing.

02 / OPAQUE PERMISSIONS

Who Has Access to What?

Answering "which repos can contractor Jane access?" requires opening 50 different repository settings pages, team memberships, and collaborator tables. There is no single manifest.

03 / NO AUDIT TRAIL

Unrecorded ClickOps

Settings changes made in GitHub's web interface don't produce commits, PR discussions, or review records. When production breaks, nobody knows who changed the webhook or status check.

04 / PRIVILEGE ESCALATION

Accidental Org Owners

In standard GitHub setups, team leads frequently request Org Admin permissions merely to manage repository settings or invite teammates, completely violating least-privilege principles.

05 / REPRODUCIBILITY

Rebuilding is Impossible

If your organization needs a staging clone, a migration, or disaster recovery, reproducing branch rules, labels, permissions, and webhook configurations by hand takes weeks of painful effort.

06 / INCONSISTENT STANDARDS

Patchwork Repo Rules

Some repos enforce 2 reviews; others enforce 0. Some delete branches on merge; others accumulate thousands of stale branches. Defaults set at the org level are easily bypassed.

The Tidyorg Rule: Anything changed by hand in the GitHub UI drifts back to the declared state on the next Terraform apply. The configuration is the only source of truth.

See Config Schema →

INTERACTIVE DEMONSTRATION

Grounded in the real dashboard. Try it yourself.

The optional Tidyorg web dashboard lets team leads view and propose changes across the organization without touching Terraform code. Every edit becomes a Pull Request, and batch mode can combine several edits into one proposal.

Payment-Org-AI Dashboard View
Repositories (3)
payment-service Go
Core payment processing & Stripe reconciliation
1 mentor2 devsprivate
auth-worker TypeScript
OAuth2 & session token validation microservice
1 mentor2 devsprivate
web-portal TypeScript
Customer dashboard and self-service web app
1 mentor2 devspublic
← Projects

payment-service Go

Core payment processing and Stripe reconciliation pipeline

Open in GitHub ↗
LANGUAGE Go
VISIBILITY 🔒 private (default)
DEFAULT BRANCH main
CONFIG FILE repositories/payment-service.yml ↗
Mentors (1)
Developers (2)
Viewers (1)
Branch Protection

Rules not specified in the repository file inherit from organization defaults.

BRANCH APPROVALS CODEOWNERS STATUS CHECK FORCE PUSH SOURCE
Issue Labels (8) Inherited from organization

Labels inherited from organization defaults. Repositories can define custom label sets.

🎉 Pull Request Created!
The dashboard writes Pull Requests against Payment-Org-AI/config. It never talks to Terraform directly.
# Loading YAML...
# Loading Terraform Plan...

* Illustrative interactive demonstration based on the authentic Tidyorg v0.1.3 dashboard design system with fictional organization and member data.

HOW IT WORKS

From YAML declaration to GitHub reality.

A clear, auditable 5-step loop. Notice the strict boundary: the dashboard proposes pull requests; humans review; Terraform executes.

STEP 01

1. Declare

Describe repos, roles, and branch protections in YAML files under config/.

YAML Files
STEP 02

2. Propose

Use the dashboard or a git branch to open a Pull Request against the config repository.

Dashboard / Git
STEP 03

3. Review

Peers and CODEOWNERS inspect the PR. CI executes terraform plan to preview changes.

Review Gate
STEP 04

4. Execute

On merge, terraform apply runs via your configured CI workflow or local container.

Terraform Engine
STEP 05

5. Reconcile

GitHub resources are adjusted to match. Any unauthorized UI changes are automatically reverted.

GitHub API
Architectural Boundary: The web dashboard never calls Terraform directly, nor does automation run without setup. Every modification travels through a standard GitHub Pull Request and review gate. Terraform plan & apply are triggered either in your CI/CD pipeline (e.g. GitHub Actions) or via a scheduled container run.

CONFIG SCHEMA

Four clean files. Zero HCL to write.

Tidyorg splits configuration by ownership boundaries. Rules are bound to roles, not people. Click a file to inspect its structure.

organization.yml HUMAN ONLY

Defines organization roles, permission mappings, global repo defaults, and public org profile.

repositories/<name>.yml HUMAN & DASHBOARD

One file per repository. Declares mentors, developers, viewers, branch protection, and CODEOWNERS.

people.yml HUMAN & DASHBOARD

Flat list of GitHub usernames that belong to the organization. Add or remove a user with a single line.

privileged.yml HUMANS ONLY • REVIEW GATED

The escalation barrier: Org Owners and privileged roles. The dashboard does not generate edits for this CODEOWNERS-protected file.

organization.yml HUMAN WRITTEN

Contract defining organization roles, base permissions, global defaults, team names, and public organization profile.

# config/organization.yml
version: 1
organization: Payment-Org-AI

# ROLES — Permission definitions bound to roles, not individual people
roles:
  head-of-engineering:
    scope: organization
    repo_permission: admin

  mentor:
    scope: repository
    repo_permission: admin

  developer:
    scope: repository
    repo_permission: push

  viewer:
    scope: repository
    repo_permission: pull

# Defaults applied to all repositories unless overridden
defaults:
  visibility: private
  has_issues: true
  delete_branch_on_merge: true
  branch_protection:
    required_reviews: 2
    require_code_owner_review: true
    require_status_checks:
      - ci/test

profile:
  name: "Payment-Org-AI"
  description: "Declarative infrastructure for Payment-Org-AI"

LEAST PRIVILEGE BY DESIGN

Two GitHub Apps. Zero shared secrets.

Tidyorg authenticates strictly through GitHub Apps using short-lived tokens. No personal access tokens (PATs) or employee credentials are ever stored.

tidyorg-engine-bot Installed on Org

Used by Terraform Reconciliation Runner

Broad permissions because it reconciles the entire organization against the configuration:

  • Organization → AdministrationRead & Write
  • Organization → MembersRead & Write
  • Repository → AdministrationRead & Write
  • Repository → Contents, Issues & WorkflowsRead & Write
  • Repository → MetadataRead-only

tidyorg-dashboard-app Single Repo Only

Installed ONLY on Payment-Org-AI/config

Deliberately narrow scopes. Only opens PRs on the signed-in user's behalf via Device Flow:

  • Repository → Contents (Config branch only)Read & Write
  • Repository → Pull RequestsRead & Write
  • Repository → Actions (Live sync status badge)Read-only
  • Repository → MetadataRead-only
What happens when an unauthorized user accesses the dashboard?

When users log in via GitHub Device Flow, their membership and role are evaluated immediately:

  • Non-organization members: Displayed an instant Access Denied screen (AccessDenied). No repositories, members, or settings are readable.
  • Non-mentors on a repository: The dashboard loads in Read-Only mode. Buttons to add members, edit repository settings, or archive are hidden/disabled.
  • GitHub-level enforcement: Write access to proposal branches requires membership in the tidyorg-dashboard-writers team. Direct API tampering will be rejected by GitHub's branch protection.

GET STARTED

Deploy in minutes with Docker.

Pre-built multi-architecture images are published to both GitHub Packages (GHCR) and Docker Hub. No cloning or local compilation required.

docker-compose.ghcr.yml • Bash / PowerShell
# 1. Download the production Compose manifest
$ curl -O https://raw.githubusercontent.com/uslanozan/Tidyorg/main/docker-compose.ghcr.yml

# 2. Scaffold your local config and state directories (first run only)
$ docker compose -f docker-compose.ghcr.yml run --rm engine scaffold

# 3. Drop your GitHub App private key at ./app.pem and configure environment variables
#    (TF_VAR_github_org_name, TF_VAR_github_app_id, TF_VAR_github_app_installation_id)

# 4. Preview your infrastructure plan
$ docker compose -f docker-compose.ghcr.yml run --rm engine plan

# 5. Apply changes once the plan looks right
$ docker compose -f docker-compose.ghcr.yml run --rm engine apply

# 6. Launch the web dashboard on http://localhost:8080
$ docker compose -f docker-compose.ghcr.yml up -d dashboard
Docker CLI • GHCR & Docker Hub Mirrors
# Pull from canonical GHCR Registry:
$ docker pull ghcr.io/uslanozan/tidyorg:0.1.3
$ docker pull ghcr.io/uslanozan/tidyorg-dashboard:0.1.3

# Or pull from automated Docker Hub mirror:
$ docker pull uslanozan/tidyorg:0.1.3
$ docker pull uslanozan/tidyorg-dashboard:0.1.3

# Run plan directly:
$ docker run --rm \
  -v "$PWD/config:/config" \
  -v "$PWD/state:/state" \
  -v "$PWD/app.pem:/secrets/app.pem:ro" \
  -e TF_VAR_github_org_name=Payment-Org-AI \
  -e TF_VAR_github_app_id=123456 \
  -e TF_VAR_github_app_installation_id=12345678 \
  ghcr.io/uslanozan/tidyorg:0.1.3 plan
HCP Terraform / Custom Remote Backend
# HCP Terraform (Terraform Cloud) Remote State:
$ docker run --rm \
  -v "$PWD/config:/config" \
  -v "$PWD/app.pem:/secrets/app.pem:ro" \
  -e TF_STATE=hcp \
  -e TF_CLOUD_ORGANIZATION=your-tf-org \
  -e TF_WORKSPACE=tidyorg-prod \
  -e TF_TOKEN_app_terraform_io=your-token \
  -e TF_VAR_github_org_name=Payment-Org-AI \
  -e TF_VAR_github_app_id=123456 \
  -e TF_VAR_github_app_installation_id=12345678 \
  ghcr.io/uslanozan/tidyorg:0.1.3 plan

TRANSPARENCY

Project status & honest limitations.

We believe in technical credibility over marketing hype. Here is an exact assessment of where Tidyorg stands today.

Current Status: v0.1.3 (Pre-1.0)

  • Functional Engine & Dashboard: Both Docker images are actively built, multi-arch tested (amd64, arm64), and available on GHCR & Docker Hub.
  • Verified Pilot Run: Tested end-to-end against a fresh disposable GitHub organization: initial scaffold, initial apply, dashboard change proposal, PR merge, reconciliation, and clean zero-diff plan.
  • Pre-1.0 Roadmap: Automated browser E2E test suites and fully disposable CI organization automation are ongoing before tagging 1.0.

⚠️ Known Limitations to Consider

  • No Built-in Code Backup: Tidyorg manages infrastructure and authorization configuration; it does not back up git commit history or PR discussion metadata. Maintain your own off-GitHub backups.
  • GitHub Free Plan Constraints: GitHub Free organizations cannot enforce branch protection rules on private repositories. Tidyorg surfaces this condition cleanly, but cannot override GitHub licensing.
  • Non-Readable Settings Drift: Certain organization settings (such as billing email and PAT security policy) are write-only or unreadable via the GitHub API. Tidyorg treats the YAML config as ground truth for these fields.

QUESTIONS & ANSWERS

Frequently asked questions.

Need more details? Check the Technical Documentation →

What if I delete a repository by mistake?+

Tidyorg is engineered with strict safeguards against accidental deletion:

1. No Hard Delete in the Dashboard: The web dashboard deliberately has no delete repository button. The most a mentor can do is archive a repository (archived: true), which freezes it as read-only while preserving all code, commit history, issues, and PR discussions.

2. Engine prevent_destroy Lock: The Terraform engine has a prevent_destroy lifecycle lock on repository resources. If a repository's YAML file is accidentally deleted from git, terraform apply will intentionally fail with an error rather than destroy the repository.

3. Deliberate Deletion Procedure: Truly deleting a repository requires intentional multi-step administrative action: removing the YAML file via reviewed PR, a platform admin manually executing terraform state rm, and then running the dedicated repository deletion script from the engine repository.

What do unauthorized users see when they log into the dashboard?+

If a user authenticates via GitHub Device Flow:

Non-members: If the user is not a member of the organization, they are immediately presented with an Access Denied screen. No repositories, members, or settings are disclosed.

Non-mentors on a repo: If the user belongs to the org but is only a developer or viewer on a specific repository, the dashboard opens in strictly Read-Only mode. Buttons to add members, change branch protections, or archive are hidden/disabled.

Does the dashboard apply Terraform directly?+

No. The dashboard does not talk to Terraform or execute applies directly. Instead, every change you make in the dashboard is batched into a standard GitHub Pull Request against your config repository. This guarantees that team review, CI status checks, and CODEOWNERS approvals are strictly honored before anything is applied.

What happens if someone changes a setting in the GitHub UI?+

The next time Terraform runs (via CI or scheduled container apply), it will detect the drift and revert the manual change back to match your YAML configuration. The YAML files are the sole source of truth.

Where is the Terraform state stored?+

By default, state is kept in the mounted ./state volume on your host, requiring zero external setup. For distributed teams, you can set TF_STATE=hcp to use HCP Terraform (Terraform Cloud) or configure a custom remote backend like AWS S3 or Google Cloud Storage.

Can anyone use the dashboard to make themselves an Org Owner?+

No. The dashboard is installed only on the configuration repository, and its UI and proposal service never generate edits for config/privileged.yml. Organization Owners and admin roles remain isolated in that file, while CODEOWNERS and branch protection require administrator review before privileged changes can be merged.

Do I need to clone the repository to use Tidyorg?+

No. The published Docker images (ghcr.io/uslanozan/tidyorg:0.1.3 and uslanozan/tidyorg:0.1.3) include the Terraform engine, provider dependencies, and starter configuration. You only need Docker and your GitHub App credentials.

Tidyorg Mark

INFRASTRUCTURE AS CODE

Bring order to your GitHub organization.

Replace fragile UI clicks with versioned, auditable, declarative configuration. Try the pre-built container or explore the open source repository.