Enterprise Live-Source Ingestion¶
Enterprise tenants can now import artifacts directly from GitHub repositories and marketplace sources using two delivery models: client-relay (Wave 1, available now) and server-side fetch (Wave 2, gated). This guide covers both flows, prerequisites, troubleshooting, and credential management.
Overview¶
Enterprise live-source ingestion bridges the gap between SkillMeat's import capabilities and enterprises running in isolated environments. Instead of pre-exporting artifacts offline, admins can:
- Client-relay (Wave 1): Use the CLI to fetch a pack from GitHub or marketplace on your local machine, then relay it to the enterprise server
- Server-side fetch (Wave 2): Configure per-tenant GitHub credentials; the server fetches and imports artifacts automatically during marketplace operations
Both paths use the same ingestion substrate — the only difference is where the fetch happens.
Wave 1: Client-Relay (Available Now)¶
Client-relay is the default and recommended approach for most enterprise deployments. Your local CLI machine fetches the pack and sends it to the enterprise server over the network.
Prerequisites¶
- SkillMeat CLI v0.56.0 or later
- GitHub API token (personal access token or GitHub App installation)
- Network access to the enterprise server
- Admin credentials for the enterprise tenant
CLI Workflow: skillmeat enterprise fetch-and-relay¶
Use this command to import a single artifact from marketplace or GitHub:
skillmeat enterprise fetch-and-relay \
--source-id <marketplace-source-id> \
--token <github-pat> \
--server-url https://your-enterprise.example.com
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
--source-id |
string | Yes | Marketplace source ID or GitHub URL (format: owner/repo) |
--token |
string | Yes | GitHub personal access token (no scopes stored on server) |
--server-url |
URL | Yes | Enterprise server URL (e.g., https://10.42.10.76:8080) |
Example:
# Import a marketplace source
skillmeat enterprise fetch-and-relay \
--source-id marketplace:claude-ops-skill-set \
--token ghp_xxxxxxxxxxxx \
--server-url https://enterprise.internal.example.com
# Import directly from GitHub
skillmeat enterprise fetch-and-relay \
--source-id miethe/meaty-ui \
--token ghp_xxxxxxxxxxxx \
--server-url https://enterprise.internal.example.com
How Client-Relay Works¶
- Local fetch — CLI fetches the artifact pack from GitHub using your token
- Local assembly — Pack is assembled (markdown, manifests, metadata)
- Server relay — Assembled pack is sent to the enterprise server via POST
/api/v1/bundles/import-pack - Server ingest — Server ingests the pack into the enterprise database
Key property: Your GitHub token is used only on your local machine. The token is never stored on the server.
Token Security¶
- The token stays on your local machine throughout the relay process
- The server never sees or stores the raw GitHub PAT
- No audit trail of token usage is recorded on the server (you are the audit owner)
- After the relay completes, the token reference is discarded
Troubleshooting Client-Relay¶
"Package fetch failed: 404 Not Found"¶
- Verify the source ID format is correct (marketplace IDs:
marketplace:<id>, GitHub repos:owner/repo) - Check that the source exists and is publicly accessible or your token has read access
- Verify your GitHub PAT is not expired
"Relay POST failed: 401 Unauthorized"¶
- Check your enterprise server credentials (
skillmeat config show) - Verify you have admin role in the enterprise tenant
- Try re-authenticating:
skillmeat auth login --enterprise
"Relay timed out"¶
- Large packages (>100 MB) may take longer; increase timeout with
--timeout 300 - Check network connectivity to the enterprise server
- Verify the server is not rate-limiting uploads
Wave 2: Server-Side Fetch (Gated Feature)¶
Wave 2 enables the server to fetch artifacts directly from GitHub on your behalf, eliminating the need for a relay step. This is useful for fully automated import workflows in air-gapped environments where the server has network access to GitHub.
Enablement¶
Server-side fetch is disabled by default. Your enterprise operator must enable it by setting the feature flag:
If this flag is not enabled, Wave 1 client-relay is used instead.
Prerequisites¶
- Wave 2 feature flag enabled on the enterprise server
- Per-tenant GitHub credentials registered via the credential management API
SKILLMEAT_ENCRYPTION_KEYstable environment variable set on the server (see §"Encryption Key Management")- F2 RBAC (
admin:*scope enforcement) live on the server
Credential Management API¶
Enterprise admins can manage per-tenant GitHub credentials via the credential management API. These credentials are stored encrypted on the server and used during marketplace import operations.
Create or Rotate a Credential¶
curl -X POST https://your-enterprise.example.com/api/v1/enterprise/git-credentials \
-H "Authorization: Bearer $ENTERPRISE_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope_type": "org",
"scope_id": "<tenant-uuid>",
"token": "ghp_xxxxxxxxxxxx",
"credential_type": "pat"
}'
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
scope_type |
string | Yes | One of: "org", "team", "developer" |
scope_id |
string | Yes | UUID of the scope owner (tenant, team, or user ID) |
token |
string | Yes | Plaintext GitHub personal access token (encrypted on server) |
credential_type |
string | No | One of: "pat" (default), "app_installation" |
Response (201 Created):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "...",
"scope_type": "org",
"scope_id": "a tenant UUID",
"credential_type": "pat",
"created_by": "admin-user-id",
"created_at": "2026-06-23T15:30:00Z",
"token_last4": "xxxx"
}
Important:
- The response includes only the last 4 characters of the token (token_last4), never the full PAT
- Once created, the raw token is encrypted and not retrievable
- To rotate the credential, POST again with the same scope_type + scope_id — the existing credential is replaced (status 200)
List Credentials¶
curl https://your-enterprise.example.com/api/v1/enterprise/git-credentials \
-H "Authorization: Bearer $ENTERPRISE_ADMIN_TOKEN"
Response:
{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "...",
"scope_type": "org",
"scope_id": "...",
"credential_type": "pat",
"created_by": "...",
"created_at": "2026-06-23T15:30:00Z",
"token_last4": null
}
],
"total": 1
}
Note: Credentials returned by GET do NOT include token_last4 (the token is never decrypted for read operations).
Delete a Credential¶
curl -X DELETE https://your-enterprise.example.com/api/v1/enterprise/git-credentials/<credential-id> \
-H "Authorization: Bearer $ENTERPRISE_ADMIN_TOKEN"
Returns 204 No Content on success.
Server-Side Import Workflow¶
Once credentials are configured, marketplace import operations automatically use server-side fetch:
- Admin triggers import — via web UI or API, specifying a marketplace source or GitHub URL
- Server checks for credential — looks up per-tenant GitHub credential for the import scope
- Server fetches pack — uses the stored credential to fetch the artifact pack from GitHub
- Server ingests pack — runs
ingest_pack_into_dbwith the fetched content - Artifacts appear — completed artifacts are visible in the collection
Encryption Key Management¶
Server-side fetch requires a stable encryption key for storing credentials. If the key changes (e.g., after a container restart), all encrypted credentials become invalid.
Key source: The server reads SKILLMEAT_ENCRYPTION_KEY environment variable at startup. If not set:
- Development: Falls back to machine-derived key (valid only for that machine)
- Production: Startup health check fails closed — the server will not start
Key rotation: If you need to rotate the encryption key (e.g., after a security incident):
- Read the full runbook:
docs/dev/ops/encryption-key-rotation-runbook.md - The runbook covers re-keying all stored credentials
- Plan maintenance downtime for the rotation procedure
Best practice: Set SKILLMEAT_ENCRYPTION_KEY in your deployment secrets before enabling Wave 2. Use a stable, high-entropy key (Fernet-format base64, 32 bytes).
Access Control¶
Wave 1 (Client-Relay)¶
- CLI user: Must have admin or enterprise role in the personal device's SkillMeat config
- Server import: Requires enterprise admin authentication when relaying the pack
- GitHub token: Used only on the client machine (never sent to server)
Wave 2 (Server-Side Fetch)¶
- Credential management API: Restricted to enterprise admins with
admin:*scope - Non-admin users: Cannot create, list, or delete credentials (403 Forbidden)
- Server-side fetch: Uses the configured per-tenant credential automatically during import
Troubleshooting¶
"Live-source fetch deferred" (Wave 1 Only)¶
Appears when trying to import new marketplace entries.
Cause: Server-side fetch is not enabled (enterprise_server_side_fetch_enabled flag is OFF).
Resolution: Use client-relay instead, or request your operator to enable Wave 2.
Credential Not Found (Wave 2)¶
Cause: No GitHub credential is configured for the import scope, and no fallback env token is available.
Error response: HTTP 422 with detail: "No GitHub credential found for tenant ..."
Resolution:
1. Create a credential via the credential management API (see §"Create or Rotate a Credential")
2. Or set the SKILLMEAT_GITHUB_TOKEN environment variable as fallback (not recommended for production)
Credential Decryption Failed (Wave 2)¶
Cause: The encryption key changed (e.g., after a container restart without stable SKILLMEAT_ENCRYPTION_KEY).
Error response: HTTP 500 with server logs showing InvalidToken or key mismatch.
Resolution:
1. Set SKILLMEAT_ENCRYPTION_KEY to a stable value in your deployment
2. Re-create all credentials (decrypted ones are lost)
3. See docs/dev/ops/encryption-key-rotation-runbook.md for systematic key rotation
Server Startup Fails with "Encryption Key Required"¶
Cause: SKILLMEAT_ENCRYPTION_KEY is not set or is machine-derived (not stable across restarts).
Resolution:
1. Generate a stable Fernet key: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
2. Set SKILLMEAT_ENCRYPTION_KEY=<generated-key> in your deployment environment
3. Restart the server
Import Hangs or Times Out¶
For Wave 1 (CLI relay):
- Increase timeout: skillmeat enterprise fetch-and-relay ... --timeout 300
- Check network connectivity between local machine and enterprise server
- Check server logs for import errors
For Wave 2 (server-side fetch): - Check server logs for GitHub API errors (rate limiting, auth failures) - Verify the credential is still valid (rotate if necessary) - Check server storage space (tmpdir fills up during large fetches)
GitHub Token Expires¶
For Wave 1: Generate a new token, pass it to the next relay command.
For Wave 2:
1. Generate a new token on GitHub
2. Rotate the credential: curl -X POST .../api/v1/enterprise/git-credentials -d '{"scope_type": "org", "scope_id": "<id>", "token": "ghp_new_token"}'
Best Practices¶
Wave 1 Security¶
- Use a personal access token with minimal scopes —
repo:readorpublic_repoonly - Create a dedicated bot account for relay operations (easy to audit and rotate)
- Rotate tokens regularly (e.g., every 90 days)
- Never commit tokens to version control; use environment variables or credential managers
Wave 2 Security¶
- Set a stable, high-entropy
SKILLMEAT_ENCRYPTION_KEYbefore enabling Wave 2 - Restrict credential management API access to enterprise admins only (automatic via
admin:*scope) - Rotate per-tenant credentials every 90 days (same as Wave 1)
- Monitor credential creation and deletion via audit logs
- Do not use a shared bot token across multiple tenants — create per-tenant credentials for isolation
Operational Workflow¶
- Small imports (1–10 artifacts): Use Wave 1 client-relay for simplicity
- Bulk imports (100+ artifacts): Use Wave 2 with server-side fetch for automation
- Air-gapped deployment: Use Wave 1 if server has no GitHub access; Wave 2 requires server ↔ GitHub connectivity
- Highly isolated environments: Prefer Wave 1 — credentials never touch the server
Summary: Wave 1 vs Wave 2¶
| Aspect | Wave 1 (Client-Relay) | Wave 2 (Server-Side) |
|---|---|---|
| Availability | Available now | Gated feature |
| Token location | Client machine only | Server (encrypted) |
| Token rotation | Manual per relay | One-time setup |
| Automation | Manual CLI command | Automatic during import |
| Network requirement | Client ↔ Server | Server ↔ GitHub |
| Best for | Ad-hoc imports, simple flows | Automated workflows, bulk imports |
| Security model | Token never stored | Token encrypted at rest |
| Complexity | Low | Medium (requires encryption key setup) |
Additional Resources¶
- Marketplace Consumer:
docs/user/guides/marketplace-consumer.md - Enterprise Features:
docs/user/guides/enterprise-features.md - GitHub Authentication:
docs/user/guides/github-authentication.md - Encryption Key Rotation:
docs/dev/ops/encryption-key-rotation-runbook.md - Enterprise Admin Workflow:
docs/user/guides/enterprise-admin-workflow.md