shipit 1.4.6

Shipit is an open source command line interface for managing merge requests, changelogs, tags, and releases using a plan and apply interface. Built with coding agent integration in mind.
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Git Shipit</title>
    <meta name="description" content="Shipit is an open source command line interface for managing merge requests, changelogs, tags, and releases using a plan and apply interface. Built with coding agent integration in mind.">
    <meta name="author" content="Tanner Rollefson">
    <link rel="canonical" href="https://gitshipit.net/">
    <link rel="icon" href="/favicon.svg" type="image/svg+xml">

    <!-- Open Graph -->
    <meta property="og:type" content="website">
    <meta property="og:url" content="https://gitshipit.net/">
    <meta property="og:title" content="Git Shipit">
    <meta property="og:description" content="Shipit is an open source command line interface for managing merge requests, changelogs, tags, and releases using a plan and apply interface. Built with coding agent integration in mind.">

    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary">
    <meta name="twitter:title" content="Git Shipit">
    <meta name="twitter:description" content="Shipit is an open source command line interface for managing merge requests, changelogs, tags, and releases using a plan and apply interface. Built with coding agent integration in mind.">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
    <style>
        :root {
            --primary: #00c8ff;
            --primary-glow: #00c8ff;
            --accent: #7eb8f7;
            --dark: #0d1117;
            --surface: #161b22;
            --surface2: #1c2330;
            --border: #263044;
            --text: #cdd9e5;
            --text-muted: #768390;
            --coffee: #FFDD00;
        }
        body {
            font-family: 'Inter', sans-serif;
            background-color: var(--dark);
            background-image:
                repeating-conic-gradient(#1a2233 0% 25%, #0d1117 0% 50%);
            background-size: 60px 60px;
            color: var(--text);
            text-align: center;
            padding: 60px 20px;
            margin: 0;
            position: relative;
        }
        body::before {
            content: '';
            position: fixed;
            inset: 0;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60'%3E%3Ctext x='5' y='45' font-size='38' opacity='0.18'%3E🚢%3C/text%3E%3C/svg%3E");
            background-size: 60px 60px;
            pointer-events: none;
            z-index: 0;
        }
        .container {
            max-width: 550px;
            margin: 0 auto;
            position: relative;
            z-index: 1;
            background: var(--surface);
            padding: 40px;
            border-radius: 16px;
            border: 1px solid var(--border);
            box-shadow: 0 10px 40px rgba(0,0,0,0.4), 0 0 60px rgba(0, 200, 255, 0.04);
        }
        h1 { margin-top: 0; font-weight: 700; font-size: 2rem; color: #e6edf3; }
        @property --border-angle {
            syntax: '<angle>';
            initial-value: 0deg;
            inherits: false;
        }

        @keyframes neon-border-rotate {
            to { --border-angle: 360deg; }
        }

        .download-card {
            border: 2px solid var(--border);
            border-radius: 12px;
            padding: 30px;
            margin: 25px 0;
            transition: all 0.3s ease;
            position: relative;
        }
        .highlight {
            border: 2px solid transparent;
            background-image:
                linear-gradient(var(--surface), var(--surface)),
                conic-gradient(
                    from var(--border-angle),
                    rgba(0, 200, 255, 0.15) 0deg,
                    rgba(0, 200, 255, 0.15) 300deg,
                    rgba(0, 200, 255, 0.5)  330deg,
                    #00c8ff                 350deg,
                    #ccf0ff                 357deg,
                    #00c8ff                 360deg
                );
            background-origin: border-box;
            background-clip: padding-box, border-box;
            transform: translateY(-2px);
            box-shadow: 0 4px 20px rgba(0, 200, 255, 0.12), 0 0 22px rgba(0, 200, 255, 0.22);
            animation: neon-border-rotate 4s linear infinite;
        }
        .btn {
            display: inline-block;
            padding: 14px 28px;
            background: var(--primary);
            color: #0d1117;
            text-decoration: none;
            border-radius: 8px;
            font-weight: bold;
            font-size: 1.1rem;
            box-shadow: 0 0 16px rgba(0, 200, 255, 0.4);
        }
        .btn:hover { filter: brightness(1.1); }

        .install-block {
            margin-top: 18px;
            text-align: left;
        }
        .install-block label {
            display: block;
            font-size: 0.78rem;
            font-weight: 600;
            color: var(--accent);
            text-transform: uppercase;
            letter-spacing: 0.05em;
            margin-bottom: 6px;
        }
        .install-cmd {
            display: flex;
            align-items: center;
            background: var(--dark);
            border-radius: 8px;
            border: 1px solid var(--border);
            overflow: hidden;
        }
        .install-cmd code {
            flex: 1;
            padding: 12px 14px;
            color: var(--primary);
            font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
            font-size: 0.82rem;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .copy-btn {
            background: none;
            border: none;
            cursor: pointer;
            padding: 10px 14px;
            color: var(--text-muted);
            font-size: 1rem;
            transition: color 0.2s;
            flex-shrink: 0;
        }
        .copy-btn:hover { color: var(--primary); }
        .copy-btn.copied { color: #68d391; }

        .other-links { margin-top: 30px; font-size: 0.85em; color: var(--text-muted); line-height: 2; }
        .other-links a { color: var(--accent); text-decoration: underline; margin: 0 5px; }

        /* Source Links Section */
        .source-links {
            margin-top: 50px;
            padding-top: 30px;
            border-top: 1px solid var(--border);
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 12px;
        }
        .source-btn {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            background-color: var(--surface2);
            color: var(--text);
            padding: 10px 18px;
            border-radius: 8px;
            text-decoration: none;
            font-weight: 600;
            font-size: 0.9rem;
            border: 1px solid var(--border);
            transition: all 0.2s ease;
        }
        .source-btn:hover {
            border-color: var(--primary);
            color: var(--primary);
            box-shadow: 0 0 12px rgba(0, 200, 255, 0.15);
        }
        .source-btn svg {
            width: 20px;
            height: 20px;
            fill: currentColor;
            flex-shrink: 0;
        }
        .source-btn img {
            width: 20px;
            height: 20px;
            flex-shrink: 0;
        }
        .source-btn.coffee-btn {
            background-color: var(--primary);
            color: #0d1117;
            border-color: var(--primary);
            box-shadow: 0 0 16px rgba(0, 200, 255, 0.4);
        }
        .source-btn.coffee-btn:hover {
            filter: brightness(1.1);
            color: #0d1117;
            border-color: var(--primary);
            box-shadow: 0 0 22px rgba(0, 200, 255, 0.6);
        }

        /* Why use shipit */
        .why-section {
            margin-top: 30px;
            text-align: left;
            border-top: 1px solid var(--border);
            padding-top: 24px;
        }
        .why-section h2 {
            font-size: 1rem;
            font-weight: 700;
            color: var(--primary);
            text-transform: uppercase;
            letter-spacing: 0.08em;
            margin: 0 0 16px 0;
        }
        .why-list {
            list-style: none;
            padding: 0;
            margin: 0;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .why-list li {
            font-size: 0.88rem;
            color: var(--text);
            line-height: 1.5;
            padding-left: 20px;
            position: relative;
        }
        .why-list li::before {
            content: 'â–¸';
            position: absolute;
            left: 0;
            color: var(--primary);
        }
        .why-list li strong {
            color: #e6edf3;
        }
    </style>
</head>
<body>

    <div class="container">
        <h1>🚢 shipit</h1>
        <p><a href="https://github.com/trollefson/shipit">Shipit</a> is an open source command line interface for managing merge requests, changelogs, tags, and releases using a plan and apply interface. Built with coding agent integration in mind.</p>

        <div id="smart-download" class="download-card highlight">
            <h3 id="os-label">Detecting your system...</h3>
            <p id="os-desc"></p>
            <div class="install-block">
                <label id="cmd-label">Install command</label>
                <div class="install-cmd">
                    <code id="install-cmd-text"></code>
                    <button class="copy-btn" id="copy-btn" title="Copy to clipboard">&#x2398;</button>
                </div>
            </div>
        </div>

        <img src="demo.gif" alt="shipit demo" style="width:100%;border-radius:10px;margin:24px 0;border:1px solid var(--border);">

        <div class="why-section">
            <h2>Why use shipit?</h2>
            <ul class="why-list">
                <li><strong>Plan before you push.</strong> Shipit separates "gather and review" from "execute." You see exactly what will be created before anything is pushed, making it safe to hand off to an AI agent.</li>
                <li><strong>Agent-native by design.</strong> Deterministic plan files, <code>--yaml</code> output, and a <code>CLAUDE.md</code> integration guide make shipit a first-class citizen in agentic coding workflows.</li>
                <li><strong>GitHub, GitLab, and more platforms to come in one binary.</strong> No plugins, no config switching. Platform is detected automatically from your remote URL.</li>
                <li><strong>Multi-repo releases.</strong> Coordinate releases across multiple repositories in a defined order from a single config file.</li>
                <li><strong>Commit enrichment.</strong> Fetches PR/MR titles from the platform API so your changelogs read like release notes, not raw git log output.</li>
                <li><strong>No runtime required.</strong> Single compiled Rust binary with no Node, Python, or dependency installation.</li>
            </ul>
        </div>

        <div class="other-links">
            <p>Looking for a different version?</p>
            <a href="https://github.com/trollefson/shipit/releases">All releases on GitHub</a>
        </div>


        <div class="source-links">
            <a class="source-btn coffee-btn" href="https://buymeacoffee.com/trollefson" target="_blank" rel="noopener">
                <img src="https://cdn.buymeacoffee.com/buttons/bmc-new-btn-logo.svg" alt="">
                Buy me a coffee
            </a>
            <a class="source-btn" href="https://github.com/trollefson/shipit" target="_blank" rel="noopener">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
                    <path d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"/>
                </svg>
                GitHub
            </a>
            <a class="source-btn" href="https://crates.io/crates/shipit" target="_blank" rel="noopener">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" aria-hidden="true">
                    <path d="M239.108 10.689 32.341 128.347a32 32 0 0 0-16 27.713v200.627a32 32 0 0 0 16.136 27.77L239.244 501.44a32 32 0 0 0 31.728.072l208-116.5a32 32 0 0 0 16.328-27.84V156.06a32 32 0 0 0-15.872-27.641L271.108 10.76a32 32 0 0 0-32 .072zm106.154 134.809L256 197.621l-89.262-52.123L256 93.375zm-202.95 36.37L234.5 232.5v112.127L142.312 292zm226.476 112.254V232.5l92.188-51.632v112.127z"/>
                </svg>
                crates.io
            </a>
            <a class="source-btn" href="https://docs.rs/shipit" target="_blank" rel="noopener">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
                    <path d="M21 5c-1.11-.35-2.33-.5-3.5-.5-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5S2.45 4.9 1 6v14.65c0 .25.25.5.5.5.1 0 .15-.05.25-.05C3.1 20.45 5.05 20 6.5 20c1.95 0 4.05.4 5.5 1.5 1.35-.85 3.8-1.5 5.5-1.5 1.65 0 3.35.3 4.75 1.05.1.05.15.05.25.05.25 0 .5-.25.5-.5V6c-.6-.45-1.25-.75-2-1zm0 13.5c-1.1-.35-2.3-.5-3.5-.5-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5 1.2 0 2.4.15 3.5.5v11.5z"/>
                </svg>
                docs.rs
            </a>
        </div>
    </div>

    <script>
        const INSTALL_SH = "curl -fsSL gitshipit.net/install | bash";
        const BREW_CMD   = "brew tap trollefson/shipit && brew install shipit";

        function detectOS() {
            const ua       = window.navigator.userAgent;
            const platform = window.navigator.platform.toLowerCase();
            const label    = document.getElementById('os-label');
            const desc     = document.getElementById('os-desc');
            const cmdEl    = document.getElementById('install-cmd-text');
            const cmdLabel = document.getElementById('cmd-label');

            const isMac = platform.includes('mac') || ua.includes('Mac');

            if (isMac) {
                label.innerText    = "Install on macOS";
                desc.innerText     = "Run this command in your terminal:";
                cmdLabel.innerText = "Shell";
                cmdEl.innerText    = INSTALL_SH;
            } else if (platform.includes('win') || ua.includes('Windows')) {
                label.innerText    = "Install on Windows";
                desc.innerText     = "Run this command in WSL:";
                cmdLabel.innerText = "Shell";
                cmdEl.innerText    = INSTALL_SH;
            } else {
                // Linux and everything else
                label.innerText    = "Install on Linux";
                desc.innerText     = "Run this command in your terminal:";
                cmdLabel.innerText = "Shell";
                cmdEl.innerText    = INSTALL_SH;
            }
        }

        document.getElementById('copy-btn').addEventListener('click', function () {
            const text = document.getElementById('install-cmd-text').innerText;
            navigator.clipboard.writeText(text).then(() => {
                this.classList.add('copied');
                this.innerHTML = '&#x2713;';
                setTimeout(() => {
                    this.classList.remove('copied');
                    this.innerHTML = '&#x2398;';
                }, 2000);
            });
        });

        detectOS();
    </script>
</body>
</html>