Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Universal Project Compiler Agent

<p align="center">
<img src="public/badges/termux.svg" alt="Termux ready" />
<img src="public/badges/fastapi.svg" alt="FastAPI powered" />
<img src="public/badges/vercel.svg" alt="Vercel ready" />
</p>

<p align="center">
<strong>Android-first compiler agent for turning requirements into secure, runnable project scaffolds.</strong><br />
<a href="public/index.html">Preview the landing page</a> · <a href="https://vercel.com/new">Deploy on Vercel</a>
</p>
Comment thread
Huynhthuongg marked this conversation as resolved.

Android-first, Termux-first development agent that transforms documents, specifications, repositories, OCR text, Markdown, or natural language requests into complete, runnable, maintainable software project scaffolds.

The original product specification is preserved in [docs/SPECIFICATION.md](docs/SPECIFICATION.md).
Expand Down Expand Up @@ -58,14 +69,26 @@ tests/ Unit tests
.github/workflows/ CI checks
```


## Vercel landing page

A polished static introduction page is included in `public/` with animated SVG badges and Vercel routing/security headers in `vercel.json`.

```bash
npm i -g vercel
vercel deploy --prod
```

If deploying from CI, provide your Vercel token as an environment secret and run `vercel deploy --prod --token "$VERCEL_TOKEN"`.

## Development

```bash
python -m pip install -e '.[dev]'
./scripts/check.sh
```

`./scripts/check.sh` runs Ruff and the full pytest suite so release checks match CI.
`./scripts/check.sh` runs Ruff and the full pytest suite so release checks match CI. The Vercel landing page lives in `public/` and is served as a static site.

## Current release

Expand Down
15 changes: 15 additions & 0 deletions public/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
document.documentElement.classList.add('js');
Comment thread
Huynhthuongg marked this conversation as resolved.

const observer = new IntersectionObserver(
Comment thread
Huynhthuongg marked this conversation as resolved.
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
}
},
{ threshold: 0.18 }
);
Comment thread
Huynhthuongg marked this conversation as resolved.

document.querySelectorAll('.reveal').forEach((node) => observer.observe(node));
5 changes: 5 additions & 0 deletions public/badges/fastapi.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/badges/termux.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/badges/vercel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 99 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Universal Project Compiler Agent turns requirements into secure runnable project scaffolds." />
<meta property="og:title" content="Universal Project Compiler Agent" />
<meta property="og:description" content="A Termux-first compiler agent with planning, safe scaffolds, tests, docs, and FastAPI automation." />
<meta property="og:type" content="website" />
Comment thread
Huynhthuongg marked this conversation as resolved.
<title>Universal Project Compiler Agent</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@500;700;800;900&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="styles.css" />
</head>
Comment thread
Huynhthuongg marked this conversation as resolved.
<body>
<div class="aurora aurora-one"></div>
<div class="aurora aurora-two"></div>
<header class="shell nav">
<a class="brand" href="#top" aria-label="Universal Project Compiler Agent home">
<span class="brand-mark">UP</span>
<span>Universal Project Compiler Agent</span>
</a>
<nav aria-label="Page sections">
<a href="#features">Features</a>
<a href="#workflow">Workflow</a>
<a href="#deploy">Deploy</a>
</nav>
</header>

<main id="top">
<section class="shell hero">
<div class="hero-copy reveal">
<p class="eyebrow">Android-first • Termux-ready • Secure by default</p>
<h1>Turn rough requirements into polished, runnable software scaffolds.</h1>
<p class="lede">Plan, compile, and ship maintainable Python/FastAPI projects with generated docs, tests, scripts, secret redaction, and low-resource workflows built for mobile developers.</p>
<div class="badge-row" aria-label="Project badges">
<img src="badges/termux.svg" alt="Termux ready" />
<img src="badges/fastapi.svg" alt="FastAPI powered" />
<img src="badges/vercel.svg" alt="Vercel ready" />
</div>
<div class="actions">
<a class="button primary" href="#features">Explore features</a>
<a class="button ghost" href="#deploy">Deploy on Vercel</a>
</div>
</div>
<aside class="terminal-card reveal" aria-label="Compilation preview">
<div class="terminal-bar"><span></span><span></span><span></span></div>
<pre><code>$ upca plan --text "# CRM Dashboard"
✓ Priority plan generated
✓ Security notes attached
✓ Tests and scripts mapped

$ upca compile --output-dir generated
✓ README.md
✓ docs/PLAN.md
✓ tests/test_smoke.py
✓ scripts/start.sh</code></pre>
</aside>
</section>

<section id="features" class="shell section reveal">
<div class="section-heading">
<p class="eyebrow">What ships</p>
<h2>Professional scaffolds with safety rails.</h2>
</div>
<div class="grid cards">
<article class="card"><span>01</span><h3>Planning engine</h3><p>Converts natural language into Critical/High/Medium/Low implementation tasks with impact and file scope.</p></article>
<article class="card"><span>02</span><h3>Safe generation</h3><p>Normalizes slugs, rejects unsafe paths, escapes Markdown, and redacts common secrets before writing files.</p></article>
<article class="card"><span>03</span><h3>Dual interface</h3><p>Use the local CLI for Termux workflows or the FastAPI service for browsers, automation, and future dashboards.</p></article>
</div>
</section>

<section id="workflow" class="shell section split reveal">
<div>
<p class="eyebrow">Workflow</p>
<h2>From prompt to project in three steps.</h2>
</div>
<ol class="steps">
<li><strong>Describe</strong><span>Paste a README, spec, OCR text, or a plain-language product idea.</span></li>
<li><strong>Review</strong><span>Inspect prioritized work items, security notes, and inferred architecture.</span></li>
<li><strong>Compile</strong><span>Generate a runnable scaffold with docs, tests, scripts, and package metadata.</span></li>
</ol>
</section>

<section id="deploy" class="shell deploy reveal">
<div>
<p class="eyebrow">Vercel-ready</p>
<h2>Static landing page configuration is included.</h2>
<p>Deploy the polished GitHub introduction page with Vercel after connecting the repository or by running the Vercel CLI with your account token.</p>
</div>
<a class="button primary" href="https://vercel.com/new" rel="noopener">Open Vercel import</a>
</section>
</main>

<footer class="shell footer">AGPL-3.0-only • Built for focused, mobile-friendly software generation.</footer>
<script src="app.js"></script>
</body>
</html>
132 changes: 132 additions & 0 deletions public/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
:root {
color-scheme: dark;
--bg: #050816;
--panel: rgba(15, 23, 42, 0.72);
--panel-strong: rgba(15, 23, 42, 0.9);
--text: #f8fafc;
--muted: #a5b4fc;
--soft: #cbd5e1;
--line: rgba(255, 255, 255, 0.14);
--accent: #8b5cf6;
--accent-two: #06b6d4;
--accent-three: #22c55e;
--shadow: 0 28px 110px rgba(0, 0, 0, 0.48);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
min-height: 100vh;
overflow-x: hidden;
background:
radial-gradient(circle at 12% 10%, rgba(139, 92, 246, 0.28), transparent 32rem),
radial-gradient(circle at 88% 4%, rgba(6, 182, 212, 0.22), transparent 30rem),
linear-gradient(135deg, #050816 0%, #0f172a 50%, #111827 100%);
color: var(--text);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

a { color: inherit; text-decoration: none; }
.shell { width: min(1120px, calc(100% - 32px)); margin: 0 auto; }
.aurora {
position: fixed;
z-index: -1;
width: 24rem;
height: 24rem;
border-radius: 999px;
filter: blur(28px);
opacity: 0.35;
animation: float 13s ease-in-out infinite alternate;
}
.aurora-one { left: -7rem; top: 18rem; background: var(--accent); }
.aurora-two { right: -8rem; top: 8rem; background: var(--accent-two); animation-delay: -4s; }
Comment thread
Huynhthuongg marked this conversation as resolved.

.nav { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 24px 0; }
.brand { display: inline-flex; align-items: center; gap: 12px; font-weight: 900; }
.brand-mark {
display: grid;
width: 42px;
height: 42px;
place-items: center;
border-radius: 14px;
background: linear-gradient(135deg, var(--accent), var(--accent-two));
box-shadow: 0 14px 36px rgba(6, 182, 212, 0.22);
}
.nav nav { display: flex; gap: 18px; color: var(--soft); font-weight: 700; }
.nav nav a:hover { color: white; }

.hero { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr); gap: 36px; align-items: center; padding: 72px 0 84px; }
.eyebrow { margin: 0 0 14px; color: var(--muted); font-weight: 900; letter-spacing: 0.12em; text-transform: uppercase; }
h1, h2, h3 { margin: 0; line-height: 1; letter-spacing: -0.055em; }
h1 { max-width: 820px; font-size: clamp(48px, 8vw, 94px); }
h2 { font-size: clamp(34px, 5vw, 58px); }
h3 { font-size: 24px; }
.lede { max-width: 720px; margin: 24px 0; color: var(--soft); font-size: clamp(18px, 2vw, 22px); line-height: 1.7; }
.badge-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 30px; }
.badge-row img { height: 34px; filter: drop-shadow(0 12px 20px rgba(0, 0, 0, 0.22)); }
.actions { display: flex; flex-wrap: wrap; gap: 14px; }
.button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 48px;
border-radius: 999px;
padding: 0 20px;
font-weight: 900;
transition: transform 0.2s ease, border-color 0.2s ease, filter 0.2s ease;
}
.button:hover { transform: translateY(-2px); filter: brightness(1.08); }
.primary { background: linear-gradient(135deg, var(--accent), var(--accent-two)); color: white; }
.ghost { border: 1px solid var(--line); background: rgba(255, 255, 255, 0.06); }
Comment thread
Huynhthuongg marked this conversation as resolved.

.terminal-card {
border: 1px solid var(--line);
border-radius: 28px;
background: linear-gradient(180deg, var(--panel), rgba(2, 6, 23, 0.78));
box-shadow: var(--shadow);
overflow: hidden;
transform: perspective(900px) rotateY(-5deg) rotateX(3deg);
}
.terminal-bar { display: flex; gap: 8px; padding: 18px; border-bottom: 1px solid var(--line); }
.terminal-bar span { width: 12px; height: 12px; border-radius: 999px; background: var(--accent-three); }
.terminal-bar span:nth-child(2) { background: #f59e0b; }
.terminal-bar span:nth-child(3) { background: #ef4444; }
pre { margin: 0; padding: 24px; overflow: auto; color: #dbeafe; font-size: 15px; line-height: 1.75; }

.section { padding: 72px 0; }
.section-heading { max-width: 700px; margin-bottom: 28px; }
.grid { display: grid; gap: 18px; }
.cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.card, .deploy, .steps li {
border: 1px solid var(--line);
border-radius: 26px;
background: var(--panel);
box-shadow: 0 20px 70px rgba(0, 0, 0, 0.22);
}
.card { padding: 24px; }
.card span { color: var(--accent-three); font-weight: 900; }
.card p, .steps span, .deploy p { color: var(--soft); line-height: 1.65; }
.split { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 28px; align-items: start; }
.steps { display: grid; gap: 14px; margin: 0; padding: 0; list-style: none; counter-reset: step; }
.steps li { display: grid; gap: 8px; padding: 22px; }
.steps strong { font-size: 22px; }
.deploy { display: flex; justify-content: space-between; gap: 24px; align-items: center; margin: 72px auto; padding: 30px; background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(6, 182, 212, 0.14)); }
.footer { padding: 24px 0 40px; color: var(--soft); }
.reveal { opacity: 1; transform: translateY(0); }
.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.8s ease, transform 0.8s ease; }
.js .reveal.visible { opacity: 1; transform: translateY(0); }

@keyframes float {
from { transform: translate3d(0, 0, 0) scale(1); }
to { transform: translate3d(3rem, -2rem, 0) scale(1.08); }
}

@media (max-width: 860px) {
.nav { align-items: flex-start; flex-direction: column; }
.nav nav { flex-wrap: wrap; }
.hero, .split, .cards { grid-template-columns: 1fr; }
.hero { padding-top: 44px; }
.terminal-card { transform: none; }
.deploy { align-items: flex-start; flex-direction: column; }
}
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ select = ["E", "F", "I", "B", "UP", "SIM"]
[tool.ruff.lint.per-file-ignores]
"app/universal_compiler_agent/server.py" = ["E501"]
"app/universal_compiler_agent/templates.py" = ["E501"]

[tool.codespell]
skip = "*.png,.git,.pytest_cache,.ruff_cache,.venv"
ignore-words-list = "thi"
41 changes: 41 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"cleanUrls": true,
"trailingSlash": false,
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "Referrer-Policy",
"value": "strict-origin-when-cross-origin"
},
{
"key": "Permissions-Policy",
"value": "camera=(), microphone=(), geolocation=()"
}
]
}
],
Comment thread
Huynhthuongg marked this conversation as resolved.
"rewrites": [
{
"source": "/",
"destination": "/index.html"
},
{
"source": "/styles.css",
"destination": "/public/styles.css"
},
{
"source": "/app.js",
"destination": "/public/app.js"
},
{
"source": "/badges/:path*",
"destination": "/public/badges/:path*"
}
]
}
Loading