Skip to content

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:

  1. 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
  2. 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

  1. Local fetch — CLI fetches the artifact pack from GitHub using your token
  2. Local assembly — Pack is assembled (markdown, manifests, metadata)
  3. Server relay — Assembled pack is sent to the enterprise server via POST /api/v1/bundles/import-pack
  4. 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:

# On the enterprise server, set:
export SKILLMEAT_ENTERPRISE_SERVER_SIDE_FETCH_ENABLED=true

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_KEY stable 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:

  1. Admin triggers import — via web UI or API, specifying a marketplace source or GitHub URL
  2. Server checks for credential — looks up per-tenant GitHub credential for the import scope
  3. Server fetches pack — uses the stored credential to fetch the artifact pack from GitHub
  4. Server ingests pack — runs ingest_pack_into_db with the fetched content
  5. 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):

  1. Read the full runbook: docs/dev/ops/encryption-key-rotation-runbook.md
  2. The runbook covers re-keying all stored credentials
  3. 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

  1. Use a personal access token with minimal scopesrepo:read or public_repo only
  2. Create a dedicated bot account for relay operations (easy to audit and rotate)
  3. Rotate tokens regularly (e.g., every 90 days)
  4. Never commit tokens to version control; use environment variables or credential managers

Wave 2 Security

  1. Set a stable, high-entropy SKILLMEAT_ENCRYPTION_KEY before enabling Wave 2
  2. Restrict credential management API access to enterprise admins only (automatic via admin:* scope)
  3. Rotate per-tenant credentials every 90 days (same as Wave 1)
  4. Monitor credential creation and deletion via audit logs
  5. Do not use a shared bot token across multiple tenants — create per-tenant credentials for isolation

Operational Workflow

  1. Small imports (1–10 artifacts): Use Wave 1 client-relay for simplicity
  2. Bulk imports (100+ artifacts): Use Wave 2 with server-side fetch for automation
  3. Air-gapped deployment: Use Wave 1 if server has no GitHub access; Wave 2 requires server ↔ GitHub connectivity
  4. 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