This is a submission for the GitHub Copilot CLI Challenge
What I Built
I built EnvHub a secure, versioned environment variable manager that finally treats your .env files with the same respect as your code.
Show the Full Application flow here https://youtu.be/54do2TvHB3Y
But before I show you what it does, let me tell you why it exists.
The Problem That Kept Happening
Every developer has done this at least once:
You're working on a feature. You pull the latest code. You run the app. It breaks. You spend 30 minutes debugging only to realize someone added a new environment variable and forgot to tell the team.
Or worse: you accidentally overwrote your .env with an old version and replaced new config with outdated values. Production keys? Gone. New API endpoints? Reverted.
I've lost count of how many times this happened to me and my team:
-
"Hey, can you Slack me the new
.env?" Insecure and lazy -
"Wait, which version of the
.envare you using?" Pure chaos - "Who changed the DATABASE_URL and when?" No audit trail whatsoever
-
"I just overwrote the new config with my old
.env..." Silent disasters
We treat code with version control with Git, pull requests, code reviews. But we treat our most sensitive configuration database passwords, API keys, encryption secrets like scratch paper.
That's insane.
So I decided to build something better.
The Vision: Git, But For Secrets
I wanted a tool that worked the way developers already think:
-
Push your
.envto a central place (likegit push) -
Pull it down on any machine (like
git pull) -
History of every change with who, what, and when (like
git log) - Encrypted so even if someone accesses the storage, they can't read the secrets
And critically: Zero-knowledge architecture. I didn't want to build another SaaS where I hold everyone's secrets. That's a liability nightmare and honestly, I wouldn't trust a random developer with my production credentials either.
The solution? You deploy EnvHub to YOUR Vercel account, with YOUR storage, encrypted with YOUR keys. I literally cannot access your data even if I wanted to.
What EnvHub Actually Does
Let me walk you through the complete experience.
The Web Dashboard
When you first log in (via GitHub OAuth no new passwords to remember), you see a clean, dark-themed dashboard.
On the left sidebar, you have your Workspace Explorer. It's organized hierarchically:
๐ Project (e.g., "my-startup")
โโโ ๐ฅ๏ธ Service (e.g., "backend-api")
โโโ ๐ต Environment (e.g., "production")
Click on any environment, and you see all your variables displayed clearly keys and values visible right there, no extra clicks needed.
Want to edit? Click the edit button, and you get a full editor. You can:
- Add variables individually one at a time with key-value inputs
-
Bulk upload paste your entire
.envfile content at once
Every save requires a change reason because six months from now, you'll want to know why someone changed the STRIPE_API_KEY.
Below the variables, you'll see the Version History table. Every single change is recorded:
| Version | Date | User | Reason |
|---|---|---|---|
| v3 | Feb 14, 2026 | @harivelu0 | Updated Stripe to production keys |
| v2 | Feb 10, 2026 | @teammate | Added Redis connection string |
| v1 | Feb 1, 2026 | @harivelu0 | Initial setup |
Click on any version to view what the variables looked like at that point in time. Full time-travel debugging. Accidentally overwrote something? Just check the previous version.
The CLI (Where the Real Power Lives)
The web dashboard is great for browsing and quick edits. But for developers who live in the terminal, the CLI is where it gets powerful.
Install it with one command:
pip install https://your-envhub-instance.vercel.app/cli/envhub_cli-2.0.3-py3-none-any.whl
Initialize it to point to your instance:
envhub init --api-url https://your-envhub-instance.vercel.app/api
Why do we need this step? Because EnvHub is self-hosted everyone deploys their own instance. Your company's EnvHub might live at envhub.mycompany.com while another team uses secrets.startup.io. The init command tells the CLI where YOUR backend lives.
Login using your existing GitHub credentials:
envhub login
This uses the GitHub CLI (gh) under the hood, so if you're already logged into gh, you're good to go. No new passwords, no separate accounts.
Now you're ready.
Push your local .env to the cloud:
envhub push -p my-startup -s backend-api -e production -r "Added new payment gateway keys"
The -r flag is the change reason required, so your team always knows why things changed. -p flag refers project name, -s refers service and -e refers environment
Pull variables to any machine:
# Print to console (great for reviewing or piping)
envhub pull -p my-startup -s backend-api -e production
# Save directly to a file
envhub pull -p my-startup -s backend-api -e production -o .env
By default, pull outputs to the console. This is intentional it lets you review what you're getting before saving it.
View the audit history:
envhub history -p my-startup -s backend-api -e production
โโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Version โ Date โ User โ Reason โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ 3 โ 2026-02-14 09:30:00 โ @harivelu0 โ Added new payment gateway keys โ
โ 2 โ 2026-02-10 14:22:00 โ @teammate โ Added Redis connection string โ
โ 1 โ 2026-02-01 11:00:00 โ @harivelu0 โ Initial setup โ
โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
New developer joining the team? envhub pull. Spinning up a new server? envhub pull. Debugging why production broke last Tuesday? envhub history.
The Security Model (I Take This Seriously)
Let me be clear about how EnvHub protects your secrets.
1. Zero-Knowledge Architecture
When you deploy EnvHub, you deploy it to your own Vercel account. Your data lives in your own Vercel Blob storage. The encryption key is your own key that you generate.
I, as the creator of EnvHub, have absolutely zero access to:
- Your Vercel account
- Your Blob storage
- Your encryption key
- Your secrets
Even if someone subpoenas me, I literally cannot hand over your data because I don't have it.
2. Encryption at Rest
Every single variable value is encrypted using Fernet (AES-128 symmetric encryption) before it's stored.
Here's what actually gets saved in Vercel Blob:
Without your ENVHUB_MASTER_KEY, those encrypted values are worthless.
3. Organization Gating
Set the ALLOWED_ORGS environment variable to your GitHub organization name, and only members of that organization can log in.
ALLOWED_ORGS=my-company,partner-org
Random person finds your EnvHub URL? They can't even access anything. Access denied.
4. Audit Everything
Every single change records:
- Who made the change (GitHub username)
- When they made it (timestamp)
- What they changed (full variable snapshot)
- Why they changed it (required change reason)
Six months later when production breaks, you'll know exactly who to ask and what changed.
How GitHub Copilot CLI Made This Possible
Here's my situation: I work in DevOps. I'm comfortable with infrastructure, CI/CD pipelines, cloud services, React, and Next.js. But building a distributable Python CLI tool? That was new territory for me.
GitHub Copilot CLI was my guide through unfamiliar terrain.
The First Conversation: "How Do I Structure This?"
I knew what I wanted to build. I didn't know how to build a proper CLI.
I asked Copilot:
"How do I create a Python CLI that can authenticate with a Next.js API using GitHub OAuth?"
Copilot gave me a clear strategy:
- Use the
typerlibrary for CLI structure (modern, type-hint based) - Use the
richlibrary for beautiful terminal output and created folder structure and initialize with code snippets - Don't reinvent auth use the GitHub CLI (
gh auth token) to get the user's existing token
That last point was the key insight. Instead of building a complex OAuth flow for the terminal, I just grab the token that's already there from the GitHub CLI. Users are already logged into gh for their daily work. Why make them log in again?
def get_auth_headers(api_url):
result = subprocess.run(["gh", "auth", "token"], capture_output=True, text=True)
token = result.stdout.strip()
return {"Authorization": f"Bearer {token}"}
Secure authentication in 4 lines of code.
The Battle: Cross-Platform Path Handling
My CLI worked perfectly on my Linux. Then I tested it on Windows.
Immediate crash.
The problem? I was building file paths with forward slashes (/), but Windows uses backslashes (\). When uploading to Vercel Blob, the paths were getting mangled.
I asked Copilot:
"My CLI works on Linu but fails on Windows because of path separators. How do I handle this?"
Copilot showed me how to normalize paths consistently:
from pathlib import Path
def normalize_path(path_str):
return Path(path_str).as_posix() # Always use forward slashes
Simple fix. Now EnvHub runs seamlessly on Windows, Mac, and Linux.
The Optimization: Smart "No-Change" Detection
Early testers reported a problem: they'd accidentally run envhub push twice and create duplicate versions with identical content. The history log was getting cluttered with meaningless entries.
I asked Copilot:
"How can I detect if the variables being pushed are identical to the current version and skip the write?"
Copilot helped me implement a comparison check on the backend:
// Check if variables actually changed
const currentBundle = await manager.getBundle(project, service, environment);
if (currentBundle && JSON.stringify(currentBundle.variables) === JSON.stringify(variables)) {
return NextResponse.json({
status: 'success',
version: currentBundle.version,
message: 'No changes detected. Version not incremented.'
});
}
Now EnvHub only creates a new version when something actually changes. Clean history, lower storage costs.
The Encryption Decision
I knew I needed encryption at rest. I had some familiarity with the options AES, RSA, and others but I wanted to make sure I picked the right approach for this specific use case.
I asked Copilot:
"What's a good symmetric encryption approach that works in both Python and Node.js?"
The answer: Fernet.
Fernet is built on AES-128-CBC with HMAC for authentication. It's secure, widely used, and has solid libraries for both Python and Node.js. Copilot pointed me to the exact packages:
- Python:
cryptographylibrary - Node.js:
fernetpackage
# Python (CLI side)
from cryptography.fernet import Fernet
key = Fernet.generate_key()
f = Fernet(key)
encrypted = f.encrypt(b"my secret value")
// Node.js (API side)
import fernet from 'fernet';
const secret = new fernet.Secret(key);
const token = new fernet.Token({ secret, ttl: 0 });
const encrypted = token.encode(value);
The right tool for the job, implemented quickly.
The Distribution Problem
Here's a challenge I didn't anticipate: how do users install the CLI?
I couldn't publish to PyPI (the public Python package index) because each user's CLI needs to point to their specific EnvHub instance. My EnvHub lives at envhub-harivelu.vercel.app. Your EnvHub lives at envhub-yourcompany.vercel.app. We can't share the same hardcoded package.
I asked Copilot:
"How can I distribute a Python CLI where each deployment has a different backend URL?"
Copilot's solution was elegant: host the .whl file on the EnvHub instance itself.
Each deployed EnvHub instance serves its own CLI package at /cli/envhub_cli-2.0.3-py3-none-any.whl. Users install directly from their instance:
pip install https://your-instance.vercel.app/cli/envhub_cli-2.0.3-py3-none-any.whl
Then they run envhub init to configure the API URL. Decentralized, self-contained, and each team gets their own setup.
Demo
๐ฅ Watch the Full Walkthrough: https://youtu.be/54do2TvHB3Y
๐ Try the Live Demo: https://env-hub-nu.vercel.app/
(Click "Continue with Demo Account" you can only access the sandboxed demo-project)
๐ Source Code: github.com/Harivelu0/EnvHub
Screenshots
The Login Experience
Clean, dark-themed login with GitHub OAuth. No new passwords.
The Dashboard
Your entire workspace at a glance. Projects, services, environments.
Variable Editor
Add variables individually or bulk upload. Change reason required.
Version History
Full audit trail. Click any version to see that point in time.
CLI in Action
Push, pull, and history right from your terminal.
Try It Yourself (Complete Setup Guide)
Want to deploy your own EnvHub? Here's the full walkthrough.
Prerequisites
Before you start, make sure you have:
- A GitHub account
- A Vercel account (free tier works)
- Python 3.8+ installed
- GitHub CLI (
gh) installed get it here
Step 1: Clone and Deploy
# Clone the repository
git clone https://github.com/Harivelu0/EnvHub.git
cd EnvHub
# Install dependencies
npm install
# Deploy to Vercel
vercel deploy
Vercel will ask you some questions. Accept the defaults. At the end, you'll get a URL like https://envhub-yourname.vercel.app.
Step 2: Create a GitHub OAuth App
- Go to GitHub Developer Settings
- Click "New OAuth App"
- Fill in:
- Application name: EnvHub (or whatever you want)
-
Homepage URL:
https://envhub-yourname.vercel.app -
Authorization callback URL:
https://envhub-yourname.vercel.app/api/auth/callback/github
- Click "Register application"
- Copy the Client ID
- Click "Generate a new client secret" and copy the Client Secret
Step 3: Create Vercel Blob Storage
- Go to Vercel Dashboard
- Click on "Storage" in the sidebar
- Click "Create Database" โ Select "Blob"
- Name it something like
envhub-storage - Copy the Read/Write Token
Step 4: Generate Your Encryption Key
Run this command to generate a secure Fernet key:
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
You'll get something like: Sn-S2vY5W4HuScQ60IG8JXiK9aIMmC-SadbyY1NxWBY=
Keep this safe! If you lose this key, you lose access to all your encrypted variables.
Step 5: Configure Environment Variables
In your Vercel Dashboard:
- Go to your EnvHub project
- Click "Settings" โ "Environment Variables"
- Add these variables:
| Variable | Value |
|---|---|
GITHUB_ID |
Your OAuth App Client ID |
GITHUB_SECRET |
Your OAuth App Client Secret |
NEXTAUTH_SECRET |
Run openssl rand -base64 32 and paste the result |
NEXTAUTH_URL |
https://envhub-yourname.vercel.app |
BLOB_READ_WRITE_TOKEN |
Your Vercel Blob token |
ENVHUB_MASTER_KEY |
Your Fernet key from Step 4 |
ALLOWED_ORGS |
Your GitHub organization name (optional but recommended) |
ALLOWED_USERS |
Your GitHub username (optional, for personal use) |
Step 6: Redeploy
vercel --prod
Step 7: Install and Configure the CLI
# Install the CLI from your instance
pip install https://envhub-yourname.vercel.app/cli/envhub_cli-2.0.3-py3-none-any.whl
# Point it to your instance
envhub init --api-url https://envhub-yourname.vercel.app/api
# Login via GitHub
envhub login
Step 8: Push Your First Environment
# Create a test .env file
echo "DATABASE_URL=postgres://localhost:5432/mydb" > .env
echo "API_KEY=sk_test_12345" >> .env
# Push it to EnvHub
envhub push -p my-project -s backend -e dev -r "Initial setup"
# Verify it worked
envhub pull -p my-project -s backend -e dev
You're done! You now have a fully functional, encrypted, versioned secret manager.
The Tech Stack
| Layer | Technology | Why |
|---|---|---|
| Frontend | Next.js 16 + React 19 | Latest features, seamless API routes |
| Styling | Tailwind CSS 4 | Fast iteration on the dark theme |
| Auth | NextAuth.js + GitHub OAuth | No new passwords, org gating built-in |
| Storage | Vercel Blob | Serverless, no database to manage |
| Encryption | Fernet (AES-128) | Industry standard, cross-platform |
| CLI | Python + Typer + Rich | Clean terminal UI, good DX |
The entire backend is serverless. No database servers to maintain, no scaling headaches. Vercel Blob handles storage, API routes handle logic.
What's Next?
EnvHub is already useful for small teams, but I have plans:
Cloud-Agnostic Storage
Currently uses Vercel Blob. Some enterprises need their data in AWS S3 or Azure Blob Storage for compliance. I'm abstracting the storage layer to support multiple providers.
Enterprise Identity (RBAC)
Right now, access control is binary: you're in the allowed org or you're not. For larger teams, I want role-based access:
- DevOps Lead โ All projects
- Backend Dev โ Backend services only
- Intern โ Read-only on dev environments
Audit Log Export
For SOC2 compliance, security teams need to export audit logs to SIEM tools (Splunk, Azure Sentinel). Adding a one-click export feature.
Lessons Learned
1. Scratch your own itch. The best tools come from real frustration. I built EnvHub because I was tired of the .env chaos. That frustration carried me through the hard parts.
2. AI accelerates learning. GitHub Copilot CLI didn't build EnvHub for me. But it helped me learn CLI development faster than I would have on my own. I still made the architecture decisions and debugged the weird issues. Copilot just shortened the learning curve.
3. Security can't be an afterthought. It would've been easier to build EnvHub as a hosted SaaS. But zero-knowledge architecture is the right choice for a secrets tool. Your secrets should be yours.
4. Developer experience matters. A secure tool that's annoying to use gets ignored. I spent real time on the CLI output formatting and dashboard UI. Good tools should feel good to use.
Conclusion
EnvHub started as frustration with the way we handle environment variables and became a tool I'm genuinely proud of.
It solves a real problem. It's secure by design. It's open source. And building it taught me that with tools like GitHub Copilot CLI, you can pick up new skills faster than ever.
If you've ever Slacked a .env file to a teammate, or overwritten new config with old values, or spent an hour debugging a missing variable EnvHub is for you.
โญ Star the repo: https://github.com/Harivelu0/EnvHub
๐ Found a bug? Open an issue
๐ฌ Questions? Drop a comment below!
Thanks for reading. Now go secure your secrets.















Top comments (0)