コードの生成からお金が入るまでを自動化する
個人開発者にとって、コードを書くこと自体は楽しくても、ビルド・デプロイ・課金設定・SEO対策といった周辺作業の繰り返しが負担になることがあります。AntigravityのAIエージェントはこれらの工程を自律的に処理できますが、それを「収益が発生するまでの一連のパイプライン」として体系的に構築するノウハウはまだ多くの人に知られていません。
パイプラインアーキテクチャの全体像
自動収益化パイプラインは5つのステージで構成されます。
ステージ構成
- 企画ステージ — キーワード分析とコンテンツ戦略の策定
- 開発ステージ — Antigravityエージェントによるコード・コンテンツ生成
- 品質ステージ — 自動テスト・リント・SEOチェック
- デプロイステージ — Cloudflare Workersへの自動デプロイ
- 収益ステージ — Stripe課金の監視と最適化
GitHub Actionsによるパイプライン定義
ワークフロー全体
# .github/workflows/auto-revenue-pipeline.yml
# AIエージェント駆動の自動収益化パイプライン
name: Auto Revenue Pipeline
on:
schedule:
- cron: '0 */4 * * *' # 4時間ごとに実行
workflow_dispatch: # 手動実行も可能
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
jobs:
# ステージ1: 企画
planning:
runs-on: ubuntu-latest
outputs:
content_brief: ${{ steps.plan.outputs.brief }}
steps:
- uses: actions/checkout@v4
- name: Analyze trends and plan content
id: plan
run: |
# キーワードトレンドの分析
python scripts/analyze_trends.py \
--api-key "$GEMINI_API_KEY" \
--existing-articles src/generated/articles.json \
--output /tmp/content_brief.json
# 結果をoutputに設定
echo "brief=$(cat /tmp/content_brief.json | jq -c .)" >> "$GITHUB_OUTPUT"
# ステージ2: コンテンツ生成
generate:
needs: planning
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate article with Antigravity Agent
run: |
BRIEF='${{ needs.planning.outputs.content_brief }}'
# Antigravityエージェントによる記事生成
# 日本語版と英語版を同時に生成
node scripts/generate-article.mjs \
--brief "$BRIEF" \
--locale ja \
--output content/articles/ja/
node scripts/generate-article.mjs \
--brief "$BRIEF" \
--locale en \
--output content/articles/en/
- name: Generate articles.json
run: node scripts/generate-content.mjs
- name: Verify JA/EN count match
run: |
JA=$(find content/articles/ja -name "*.mdx" | wc -l)
EN=$(find content/articles/en -name "*.mdx" | wc -l)
echo "JA=$JA EN=$EN"
if [ "$JA" != "$EN" ]; then
echo "❌ Count mismatch!" && exit 1
fi
- uses: actions/upload-artifact@v4
with:
name: generated-content
path: |
content/articles/
src/generated/
# ステージ3: 品質チェック
quality:
needs: generate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: generated-content
- name: Run quality checks
run: |
# MDXの文法チェック
npx mdx-lint content/articles/
# SEOチェック(タイトル長、description長、キーワード密度)
node scripts/seo-check.mjs
# リンク切れチェック
node scripts/check-internal-links.mjs
# ステージ4: デプロイ
deploy:
needs: quality
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: generated-content
- name: Deploy to Cloudflare Workers
run: |
npm ci
npx wrangler deploy --env production
- name: Verify deployment
run: |
# デプロイ後のヘルスチェック
SLUG=$(jq -r '.slug' /tmp/content_brief.json)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"https://your-site.com/articles/category/$SLUG")
if [ "$STATUS" != "200" ]; then
echo "❌ Deploy verification failed: HTTP $STATUS"
exit 1
fi
echo "✅ Article live: HTTP $STATUS"Antigravityエージェントによるコンテンツ生成スクリプト
// scripts/generate-article.mjs
// Antigravityエージェントが生成するコンテンツの制御スクリプト
import { GoogleGenerativeAI } from "@google/generative-ai";
import { writeFileSync, mkdirSync } from "fs";
import { dirname } from "path";
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
interface ContentBrief {
topic: string;
category: string;
keywords: string[];
targetLevel: "beginner" | "intermediate" | "advanced";
premium: boolean;
}
async function generateArticle(
brief: ContentBrief,
locale: "ja" | "en"
): Promise<string> {
const systemPrompt = locale === "ja"
? `あなたはAntigravity Labの技術ライターです。
丁寧で解りやすく、誠実さが伝わる文体で書いてください。
文字数: 3,000〜5,000文字
H2を4〜6個、FAQ3つ以上、コード例1つ以上を含めてください。`
: `You are a technical writer for Antigravity Lab.
Write in a warm, approachable, and informative tone.
Word count: 1,500-2,500 words
Include 4-6 H2 headings, 3+ FAQs, and at least 1 code example.`;
const response = await model.generateContent({
contents: [{ role: "user", parts: [{ text: `
${systemPrompt}
Topic: ${brief.topic}
Category: ${brief.category}
Keywords: ${brief.keywords.join(", ")}
Level: ${brief.targetLevel}
Generate a complete MDX article with frontmatter.` }] }]
});
return response.response.text();
}
// メイン実行
const brief = JSON.parse(process.argv.find(a =>
a.startsWith("--brief="))?.slice(8) || "{}");
const locale = process.argv.find(a =>
a.startsWith("--locale="))?.slice(9) || "ja";
const output = process.argv.find(a =>
a.startsWith("--output="))?.slice(9) || "content/articles/";
const article = await generateArticle(brief, locale as "ja" | "en");
const filePath = `${output}${brief.category}/${brief.slug}.mdx`;
mkdirSync(dirname(filePath), { recursive: true });
writeFileSync(filePath, article);
console.log(`✅ Generated: ${filePath}`);
// 期待する出力:
// ✅ Generated: content/articles/ja/agents/new-article-slug.mdxStripe課金監視の自動化
// scripts/monitor-revenue.mjs
// 収益モニタリングと自動最適化スクリプト
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
interface RevenueReport {
period: string;
totalRevenue: number;
newSubscribers: number;
churnRate: number;
topPerformingArticles: string[];
recommendations: string[];
}
async function generateRevenueReport(): Promise<RevenueReport> {
// Stripeから直近の収益データを取得
const charges = await stripe.charges.list({
created: {
gte: Math.floor(Date.now() / 1000) - 86400 // 過去24時間
},
limit: 100
});
const subscriptions = await stripe.subscriptions.list({
status: "active",
limit: 100
});
const totalRevenue = charges.data.reduce(
(sum, charge) => sum + charge.amount, 0
) / 100; // 円単位に変換
// 解約リスクの分析
const canceledRecent = await stripe.subscriptions.list({
status: "canceled",
created: {
gte: Math.floor(Date.now() / 1000) - 604800 // 過去7日
}
});
const churnRate = canceledRecent.data.length /
(subscriptions.data.length + canceledRecent.data.length);
return {
period: new Date().toISOString().split("T")[0],
totalRevenue,
newSubscribers: subscriptions.data.filter(
s => s.created > Date.now() / 1000 - 86400
).length,
churnRate,
topPerformingArticles: [], // Analytics APIから取得
recommendations: churnRate > 0.05
? ["解約率が5%を超えています。リテンション施策の検討を推奨"]
: ["解約率は安定しています"]
};
}
const report = await generateRevenueReport();
console.log(JSON.stringify(report, null, 2));
// 期待する出力例:
// {
// "period": "2026-03-22",
// "totalRevenue": 12800,
// "newSubscribers": 3,
// "churnRate": 0.023,
// "topPerformingArticles": [],
// "recommendations": ["解約率は安定しています"]
// }NemoClawとの統合でパイプラインを保護
CI/CDパイプラインにNemoClawのOpenShellを統合することで、以下のセキュリティ制約を自動的に適用できます。
コンテンツ生成ステージでは、エージェントがcontent/ディレクトリのみに書き込み可能とし、src/や.envへの書き込みをブロック。デプロイステージでは、Cloudflare APIとGitHubのみへのネットワークアクセスを許可し、それ以外のネットワーク通信を遮断。課金監視ステージでは、Stripe APIの読み取り操作のみを許可し、サブスクリプションの変更や削除は人間の承認を経由するよう制限します。
全体を振り返って — パイプラインは「自走する仕組み」の設計図
自動収益化CI/CDパイプラインは、コンテンツの企画から課金までを一本の線で繋ぐ仕組みです。Antigravityのエージェントがコードとコンテンツを生成し、GitHub Actionsが品質チェックとデプロイを担い、Stripeが課金を処理する——各ステージが自動的に連携することで、開発者はプロダクトの価値向上に集中できます。
最も大切なのは、完璧なパイプラインを一度で構築しようとしないことです。まずはコンテンツ生成と自動デプロイから始め、品質チェックと課金監視を段階的に追加していきましょう。
さらに詳しい自動化の手法については、Antigravity × Stripe マネタイズガイドやAntigravity マネタイズ完全攻略もぜひ参考にしてください。
個人開発12年の現場で実感したこと
線引きするときの3つの判断軸
- 失敗時の影響が金銭やユーザー体験にどれだけ波及するか
- 復旧オペレーションが明文化されているか
- 観測ログから人間が再現できる粒度に整っているか