{"id":28225187,"url":"https://github.com/smooai/config","last_synced_at":"2026-05-11T02:29:08.410Z","repository":{"id":293336768,"uuid":"958828527","full_name":"SmooAI/config","owner":"SmooAI","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-23T03:09:47.000Z","size":861,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-23T04:11:56.297Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SmooAI.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-01T20:38:52.000Z","updated_at":"2026-02-23T03:09:51.000Z","dependencies_parsed_at":"2025-08-05T06:19:54.894Z","dependency_job_id":"a20d58b2-fa46-42f3-bd9e-99988bf0bf9f","html_url":"https://github.com/SmooAI/config","commit_stats":null,"previous_names":["smooai/config"],"tags_count":0,"template":false,"template_full_name":"SmooAI/library-template","purl":"pkg:github/SmooAI/config","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmooAI%2Fconfig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmooAI%2Fconfig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmooAI%2Fconfig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmooAI%2Fconfig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SmooAI","download_url":"https://codeload.github.com/SmooAI/config/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmooAI%2Fconfig/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29807689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T22:43:48.403Z","status":"ssl_error","status_checked_at":"2026-02-24T22:43:18.536Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-18T10:09:13.004Z","updated_at":"2026-05-11T02:29:08.393Z","avatar_url":"https://github.com/SmooAI.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- Improved compatibility of back to top link: See: https://github.com/othneildrew/Best-README-Template/pull/73 --\u003e\n\n\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://smoo.ai\"\u003e\n    \u003cimg src=\"images/logo.png\" alt=\"SmooAI Logo\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003c!-- ABOUT THE PROJECT --\u003e\n\n## About SmooAI\n\nSmooAI is an AI-powered platform for helping businesses multiply their customer, employee, and developer experience.\n\nLearn more on [smoo.ai](https://smoo.ai)\n\n## SmooAI Packages\n\nCheck out other SmooAI packages at [smoo.ai/open-source](https://smoo.ai/open-source)\n\n## About @smooai/config\n\n**Type-safe config, secrets, and feature flags for every layer of your stack** -- One schema, one API, every language. Rename a key and every call site is a compile error, not a 3 AM page.\n\n![NPM Version](https://img.shields.io/npm/v/%40smooai%2Fconfig?style=for-the-badge)\n![NPM Downloads](https://img.shields.io/npm/dw/%40smooai%2Fconfig?style=for-the-badge)\n![NPM Last Update](https://img.shields.io/npm/last-update/%40smooai%2Fconfig?style=for-the-badge)\n\n![GitHub License](https://img.shields.io/github/license/SmooAI/config?style=for-the-badge)\n![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/SmooAI/config/release.yml?style=for-the-badge)\n![GitHub Repo stars](https://img.shields.io/github/stars/SmooAI/config?style=for-the-badge)\n\n---\n\n### What you get\n\n- **Three tiers, one schema** -- public config, secrets, and feature flags defined once with Zod/Valibot/ArkType/Effect, validated everywhere they're read.\n- **Strongly-typed keys** -- `defineConfig()` gives you `PublicConfigKeys`, `SecretConfigKeys`, and `FeatureFlagKeys` with full inference. Mis-typed keys fail at compile time, not at runtime.\n- **Any environment, any key** -- same API for `development`, `staging`, `production`. Override per-stage without touching code.\n- **Zero-latency cold starts** -- values are baked into the bundle as env vars (Next.js, Vite) or resolved in-memory from a local runtime (server). No network round-trip on the hot path.\n- **Browser, server, framework-native** -- the same typed keys read cleanly from React client components, Server Components, Next.js, Vite, or plain Node.\n- **Live feature flags** -- toggled from the dashboard without a redeploy, but still typed.\n- **Native clients in every language** -- TypeScript, Python, Rust, Go, .NET (C#) all read from the same source of truth.\n\n---\n\n### Languages / SDKs\n\nPick the SDK that matches your service. Every client reads the same schema, the same encrypted bundle, and the same config API — so a key renamed in one language ripples through all of them.\n\n| SDK            | One-liner                                                                                               | README                                           |\n| -------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |\n| **TypeScript** | Primary SDK. Schema definition, Next.js / Vite plugins, server runtime, React hooks.                    | [`README.md` (this file)](#about-smooaiconfig)   |\n| **Python**     | Pydantic-validated schemas, sync `ConfigClient`, `LocalConfigManager` + `ConfigManager`, baked runtime. | [`python/README.md`](python/README.md)           |\n| **Go**         | Native struct schemas, thread-safe `ConfigClient` / `ConfigManager`, baked-blob runtime.                | [`go/config/README.md`](go/config/README.md)     |\n| **Rust**       | `JsonSchema`-derived schemas, async `ConfigClient`, sync `ConfigManager`, baked-blob runtime.           | [`rust/config/README.md`](rust/config/README.md) |\n| **.NET**       | Roslyn source-generated typed keys, OAuth2 `SmooConfigClient`, AES-GCM `SmooConfigRuntime`.             | [`dotnet/README.md`](dotnet/README.md)           |\n\n---\n\n### Install\n\n```sh\npnpm add @smooai/config\n```\n\n---\n\n## Quick Start (TypeScript)\n\n### 1. Define your configuration schema\n\nUse `defineConfig()` with any [StandardSchema](https://github.com/standard-schema/standard-schema)-compliant library (Zod, Valibot, ArkType, Effect Schema) or the built-in `StringSchema`, `BooleanSchema`, and `NumberSchema` helpers:\n\n```typescript\n// .smooai-config/config.ts\nimport { defineConfig, StringSchema, BooleanSchema, NumberSchema } from '@smooai/config';\nimport { z } from 'zod';\n\nconst config = defineConfig({\n    publicConfigSchema: {\n        apiBaseUrl: z.string().url(),\n        maxRetries: NumberSchema,\n        enableDebug: BooleanSchema,\n    },\n    secretConfigSchema: {\n        databaseUrl: z.string().url(),\n        apiKey: StringSchema,\n    },\n    featureFlagSchema: {\n        enableNewUi: BooleanSchema,\n        betaFeatures: BooleanSchema,\n    },\n});\n\nexport default config;\n\n// Extract typed key objects for use throughout your app\nexport const { FeatureFlagKeys, PublicConfigKeys, SecretConfigKeys } = config;\n```\n\n`defineConfig()` automatically maps camelCase keys to `UPPER_SNAKE_CASE`:\n\n```typescript\nFeatureFlagKeys.ENABLE_NEW_UI; // \"ENABLE_NEW_UI\"\nPublicConfigKeys.API_BASE_URL; // \"API_BASE_URL\"\nSecretConfigKeys.DATABASE_URL; // \"DATABASE_URL\"\n```\n\n### 2. Add to `tsconfig.json`\n\n```json\n{\n    \"compilerOptions\": { ... },\n    \"include\": [\"src/**/*\", \".smooai-config/**/*.ts\"]\n}\n```\n\n---\n\n## Next.js Integration\n\n### Inject config into `next.config.ts`\n\nUse `withSmooConfig()` to inject feature flags and public config as `NEXT_PUBLIC_` environment variables, with per-stage overrides:\n\n```typescript\n// next.config.ts\nimport { withSmooConfig } from '@smooai/config/nextjs/withSmooConfig';\n\nconst nextConfig = withSmooConfig({\n    default: {\n        featureFlags: { enableNewUi: false, betaFeatures: false },\n        publicConfig: { apiBaseUrl: 'https://api.smooai.com', maxRetries: 3 },\n    },\n    development: {\n        featureFlags: { enableNewUi: true },\n        publicConfig: { apiBaseUrl: 'http://localhost:3000' },\n    },\n});\n\nexport default nextConfig;\n```\n\nThis sets environment variables like `NEXT_PUBLIC_FEATURE_FLAG_ENABLE_NEW_UI=true` and `NEXT_PUBLIC_CONFIG_API_BASE_URL=http://localhost:3000` based on the current stage.\n\n### Read config in React client components\n\n```tsx\nimport { getClientFeatureFlag, getClientPublicConfig } from '@smooai/config/client';\n\nfunction MyComponent() {\n    const isNewUi = getClientFeatureFlag('enableNewUi');\n    const apiUrl = getClientPublicConfig('apiBaseUrl');\n\n    if (!isNewUi) return \u003cLegacyUI /\u003e;\n    return \u003cNewUI apiUrl={apiUrl} /\u003e;\n}\n```\n\nThese functions check `NEXT_PUBLIC_FEATURE_FLAG_*` and `NEXT_PUBLIC_CONFIG_*` env vars automatically -- no provider needed, no loading state.\n\n### Server Components + Client hydration (zero loading flash)\n\nFor apps that need runtime config from a config server, use `getConfig` on the server and `SmooConfigProvider` to hydrate client components:\n\n```tsx\n// app/layout.tsx (Server Component)\nimport { getConfig, SmooConfigProvider } from '@smooai/config/nextjs';\n\nexport default async function RootLayout({ children }: { children: React.ReactNode }) {\n    const config = await getConfig({\n        environment: 'production',\n        fetchOptions: { next: { revalidate: 60 } },\n    });\n\n    return (\n        \u003chtml\u003e\n            \u003cbody\u003e\n                \u003cSmooConfigProvider\n                    initialValues={config}\n                    baseUrl={process.env.SMOOAI_CONFIG_API_URL}\n                    apiKey={process.env.SMOOAI_CONFIG_API_KEY}\n                    orgId={process.env.SMOOAI_CONFIG_ORG_ID}\n                    environment=\"production\"\n                \u003e\n                    {children}\n                \u003c/SmooConfigProvider\u003e\n            \u003c/body\u003e\n        \u003c/html\u003e\n    );\n}\n```\n\n```tsx\n// Any client component -- values available synchronously (pre-seeded from SSR)\nimport { usePublicConfig, useFeatureFlag } from '@smooai/config/nextjs';\n\nfunction Dashboard() {\n    const { value: apiUrl } = usePublicConfig\u003cstring\u003e('API_BASE_URL');\n    const { value: enableNewUi } = useFeatureFlag\u003cboolean\u003e('ENABLE_NEW_UI');\n    return (\n        \u003cdiv\u003e\n            API: {apiUrl}, New UI: {String(enableNewUi)}\n        \u003c/div\u003e\n    );\n}\n```\n\n---\n\n## Vite Integration\n\n### Vite plugin\n\n```typescript\n// vite.config.ts\nimport { defineConfig } from 'vite';\nimport { smooConfigPlugin } from '@smooai/config/vite/smooConfigPlugin';\n\nexport default defineConfig({\n    plugins: [\n        smooConfigPlugin({\n            featureFlags: { enableNewUi: true, betaFeatures: false },\n            publicConfig: { apiBaseUrl: 'http://localhost:3000' },\n        }),\n    ],\n});\n```\n\nThen read values the same way as Next.js -- `getClientFeatureFlag` and `getClientPublicConfig` from `@smooai/config/client` check `VITE_FEATURE_FLAG_*` and `VITE_CONFIG_*` automatically.\n\n### Preload config (optional)\n\nFor runtime config from a config server, start fetching before React mounts:\n\n```tsx\n// main.tsx\nimport { preloadConfig, ConfigProvider } from '@smooai/config/vite';\nimport { createRoot } from 'react-dom/client';\n\npreloadConfig({ environment: 'production' });\n\ncreateRoot(document.getElementById('root')!).render(\n    \u003cConfigProvider baseUrl=\"https://config.smooai.dev\" apiKey=\"your-public-key\" orgId=\"your-org-id\" environment=\"production\"\u003e\n        \u003cApp /\u003e\n    \u003c/ConfigProvider\u003e,\n);\n```\n\n---\n\n## Server-Side Config Access\n\nFor Node.js server code, use `buildConfigObject` to get sync and async accessors with full type safety:\n\n```typescript\nimport buildConfigObject from '@smooai/config/platform/server';\nimport config, { PublicConfigKeys, SecretConfigKeys, FeatureFlagKeys } from './.smooai-config/config';\n\nconst configObj = buildConfigObject(config);\n\n// Sync access (uses worker threads)\nconst dbUrl = configObj.secretConfig.getSync(SecretConfigKeys.DATABASE_URL);\nconst apiUrl = configObj.publicConfig.getSync(PublicConfigKeys.API_BASE_URL);\nconst isNewUi = configObj.featureFlag.getSync(FeatureFlagKeys.ENABLE_NEW_UI);\n\n// Async access\nconst apiKey = await configObj.secretConfig.getAsync(SecretConfigKeys.API_KEY);\n```\n\n### How `.getSync()` works (and how to ship it in any bundled compute)\n\nSync accessors run an async config read to completion on the caller thread via\n[`synckit`](https://github.com/un-ts/synckit) — a Node `Worker` pool +\n`Atomics.wait` on a `SharedArrayBuffer`. `createSyncFn` only accepts a\n`file://` URL, so the worker body has to live on disk. The SDK resolves it in\ntwo stages:\n\n1. **Sidecar file** — `sync-worker.mjs` sitting next to the compiled SDK entry\n   (i.e. resolved via `new URL('./sync-worker.mjs', import.meta.url)` from\n   `dist/server/index.mjs`). This is the normal case for plain Node resolution\n   with no bundling — `node_modules/@smooai/config/dist/server/sync-worker.mjs`\n   is already there. It's also the preferred case when bundlers copy the\n   sidecar into the deploy output. **Zero `/tmp` writes.**\n\n2. **Extract-to-`/tmp` fallback** — if the sidecar isn't on disk at that path\n   (e.g. a bundler inlined the SDK entry into a single file and didn't copy\n   the sidecar), the SDK writes an embedded copy of the worker source to\n   `mkdtempSync()/sync-worker.mjs` once per process and hands that path to\n   synckit. One ~1-2 MiB write at cold start, amortised across every sync\n   read for the lifetime of the process. Works anywhere with a writable temp\n   dir.\n\nBoth paths are transparent — your code is identical either way. Which path\nyou land on depends on how your compute is packaged.\n\n#### Plain Node (no bundling)\n\nZero config. The SDK resolves `node_modules/@smooai/config/dist/server/sync-worker.mjs`\ndirectly — path (1) every time.\n\n#### Any bundled compute (Lambda, Cloud Run, ECS, container, Worker, etc.)\n\nThe rule is universal: **if your build inlines the SDK entry into a single\noutput file, you need to ship `sync-worker.mjs` next to that output** (or accept\npath (2)'s `/tmp` write once per cold start).\n\nThe source path is always:\n\n```\nnode_modules/@smooai/config/dist/server/sync-worker.mjs\n```\n\nThe destination is alongside whichever file ends up being your runtime's\n`import.meta.url` anchor — typically the bundled handler `.mjs` / `.js`.\n\nRecipes for common setups:\n\n**esbuild — explicit copy plugin**\n\n```ts\n// build.ts\nimport { build } from 'esbuild';\nimport { copy } from 'esbuild-plugin-copy';\n\nawait build({\n    entryPoints: ['src/handler.ts'],\n    outdir: 'dist',\n    bundle: true,\n    format: 'esm',\n    platform: 'node',\n    plugins: [\n        copy({\n            assets: {\n                from: 'node_modules/@smooai/config/dist/server/sync-worker.mjs',\n                to: 'dist/sync-worker.mjs',\n            },\n        }),\n    ],\n});\n```\n\n**tsup — `onSuccess` hook**\n\n```ts\n// tsup.config.ts\nexport default defineConfig({\n    entry: ['src/handler.ts'],\n    format: ['esm'],\n    onSuccess: 'cp node_modules/@smooai/config/dist/server/sync-worker.mjs dist/sync-worker.mjs',\n});\n```\n\n**Serverless Framework — `package.include`**\n\n```yaml\npackage:\n    patterns:\n        - 'node_modules/@smooai/config/dist/server/sync-worker.mjs'\n```\n\nOr copy into the handler dir as a build step and include from there.\n\n**AWS SAM — `CodeUri` + build script**\n\nAdd a `Makefile` / build script that copies `sync-worker.mjs` into the\n`BuildArtifactPath` alongside your handler.\n\n**SST (AWS) — per-function or via `$transform`**\n\n```typescript\n// sst.config.ts — per function\nnew sst.aws.Function('Api', {\n    handler: 'src/api.handler',\n    copyFiles: [{ from: 'node_modules/@smooai/config/dist/server/sync-worker.mjs' }],\n});\n\n// Or at the stack level via $transform (every Function gets it automatically)\n$transform(sst.aws.Function, (fn) =\u003e {\n    fn.copyFiles = [...(fn.copyFiles ?? []), { from: 'node_modules/@smooai/config/dist/server/sync-worker.mjs' }];\n});\n```\n\n**Docker container (ECS, Cloud Run, anywhere)**\n\n```dockerfile\n# After your main build step, ensure the sidecar is next to the bundled entry.\nCOPY --from=build /app/dist/server.mjs /app/\nCOPY --from=build /app/node_modules/@smooai/config/dist/server/sync-worker.mjs /app/\nCMD [\"node\", \"server.mjs\"]\n```\n\nIf your build step keeps `node_modules` in the final image, no extra copy is\nneeded — the SDK resolves the sidecar from `node_modules/` path (1) directly.\n\n#### When the sidecar truly can't be shipped\n\nPath (2) — the `/tmp` extraction — is the safety net. One ~1-2 MiB write at\ncold start, then synckit re-uses the file for the rest of the process lifetime.\nLambda's 512 MiB–10 GiB `/tmp` easily absorbs this; containers with an ephemeral\n`/tmp` work the same way. **You can ignore this whole section and `.getSync()`\nwill still work** — you're just paying one filesystem write per cold start.\n\n#### Edge runtimes (Vercel Edge, Cloudflare Workers)\n\nThese runtimes don't expose Node's `worker_threads` at all, so `.getSync()` is\na no-go there by design. Use `.get()` (async) everywhere that needs to run on\nthe edge. The error surface makes this explicit if you try.\n\n---\n\n## React Hooks (framework-agnostic)\n\nFor any React app using the runtime config client:\n\n```tsx\nimport { ConfigProvider, usePublicConfig, useFeatureFlag } from '@smooai/config/react';\n\nfunction App() {\n    return (\n        \u003cConfigProvider baseUrl=\"https://config.smooai.dev\" apiKey=\"your-api-key\" orgId=\"your-org-id\" environment=\"production\"\u003e\n            \u003cMyComponent /\u003e\n        \u003c/ConfigProvider\u003e\n    );\n}\n\nfunction MyComponent() {\n    const { value: apiUrl, isLoading, error } = usePublicConfig\u003cstring\u003e('API_BASE_URL');\n    const { value: enableNewUi } = useFeatureFlag\u003cboolean\u003e('ENABLE_NEW_UI');\n\n    if (isLoading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\n    if (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n\n    return (\n        \u003cdiv\u003e\n            API URL: {apiUrl}, New UI: {String(enableNewUi)}\n        \u003c/div\u003e\n    );\n}\n```\n\n---\n\n## SDK Runtime Client\n\nAll language implementations include a runtime client for fetching configuration values from the Smoo AI config server with local caching.\n\n### Environment Variables\n\n| Variable                | Description                                            | Required |\n| ----------------------- | ------------------------------------------------------ | -------- |\n| `SMOOAI_CONFIG_API_URL` | Base URL of the config API                             | Yes      |\n| `SMOOAI_CONFIG_API_KEY` | Bearer token for authentication                        | Yes      |\n| `SMOOAI_CONFIG_ORG_ID`  | Organization ID                                        | Yes      |\n| `SMOOAI_CONFIG_ENV`     | Default environment name (defaults to `\"development\"`) | No       |\n\n### TypeScript Client\n\n```typescript\nimport { ConfigClient } from '@smooai/config/platform/client';\n\n// Zero-config (reads from env vars)\nconst client = new ConfigClient();\n\n// Or explicit\nconst client = new ConfigClient({\n    baseUrl: 'https://config.smooai.dev',\n    apiKey: 'your-api-key',\n    orgId: 'your-org-id',\n    environment: 'production',\n});\n\nconst apiUrl = await client.getValue('API_BASE_URL');\nconst allValues = await client.getAllValues();\nclient.invalidateCache();\n```\n\n---\n\n## Configuration Tiers\n\n| Tier              | Purpose                 | Examples                                 |\n| ----------------- | ----------------------- | ---------------------------------------- |\n| **Public**        | Client-visible settings | API URLs, feature toggles, UI config     |\n| **Secret**        | Server-side only        | Database URLs, API keys, JWT secrets     |\n| **Feature Flags** | Runtime toggles         | A/B tests, gradual rollouts, beta access |\n\n### Security: B2M Key Restrictions\n\n| Operation            | B2M (Public Key)  | M2M (Secret Key) |\n| -------------------- | ----------------- | ---------------- |\n| Read public values   | Yes               | Yes              |\n| Read feature flags   | Yes               | Yes              |\n| Read secret values   | **No** (filtered) | Yes              |\n| Write config values  | **No** (403)      | Yes              |\n| Delete config values | **No** (403)      | Yes              |\n\n**Browser-to-Machine (B2M)** keys are designed for browser clients. Secret-tier values are automatically filtered. B2M keys are read-only for public and feature flag tiers.\n\n**Machine-to-Machine (M2M)** keys have full access to all tiers and write operations.\n\n---\n\n## Multi-Language Support\n\n@smooai/config has native implementations in Python, Rust, Go, and .NET (C#) alongside the primary TypeScript package. Every client reads the same encrypted bundle, the same schema, and the same config API. See the per-SDK READMEs linked above for full usage docs — the snippets below are five-line orientation only.\n\n### Python — see [`python/README.md`](python/README.md)\n\n```sh\npip install smooai-config\n# or: uv add smooai-config\n```\n\n```python\nfrom smooai_config.client import ConfigClient\n\nwith ConfigClient() as client:  # reads SMOOAI_CONFIG_* env vars\n    value = client.get_value(\"API_URL\", environment=\"production\")\n```\n\n### Rust — see [`rust/config/README.md`](rust/config/README.md)\n\n```sh\ncargo add smooai-config\n```\n\n```rust\nuse smooai_config::ConfigClient;\n\nlet mut client = ConfigClient::from_env();\nlet value = client.get_value(\"API_URL\", None).await?;\n```\n\n### Go — see [`go/config/README.md`](go/config/README.md)\n\n```sh\ngo get github.com/SmooAI/config/go/config\n```\n\n```go\nimport \"github.com/SmooAI/config/go/config\"\n\nclient := config.NewConfigClientFromEnv()\ndefer client.Close()\nvalue, _ := client.GetValue(\"API_URL\", \"production\")\n```\n\n### .NET — see [`dotnet/README.md`](dotnet/README.md)\n\n```sh\ndotnet add package SmooAI.Config\n```\n\n```csharp\nusing SmooAI.Config;\nusing SmooAI.Config.Runtime;\n\nvar runtime = SmooConfigRuntime.Load();  // reads SMOO_CONFIG_KEY_FILE + SMOO_CONFIG_KEY\nusing var client = new SmooConfigClient(options);\nvar apiUrl = await Public.ApiUrl.ResolveAsync(runtime, client);\n```\n\n---\n\n## Development\n\n### Prerequisites\n\n- Node.js 22+, pnpm 10+\n- Python 3.13+ with uv (for Python package)\n- Rust toolchain (for Rust package)\n- Go 1.22+ (for Go package)\n\n### Commands\n\n```sh\npnpm install               # Install dependencies\npnpm build                 # Build all packages (TS, Python, Rust, Go)\npnpm test                  # Run all tests (Vitest, pytest, cargo test, go test)\npnpm lint                  # Lint all code (oxlint, ruff, clippy, go vet)\npnpm format                # Format all code (oxfmt, ruff, cargo fmt, gofmt)\npnpm typecheck             # Type check (tsc, basedpyright, cargo check)\npnpm check-all             # Full CI parity check\n```\n\n### Schema Libraries\n\nSupports Zod, Valibot, ArkType, Effect Schema, and built-in schema types. See [SCHEMA_USAGE.md](SCHEMA_USAGE.md) for examples with each library.\n\n---\n\n## Contributing\n\nContributions are welcome! This project uses [changesets](https://github.com/changesets/changesets) to manage versions and releases.\n\n1. Fork the repository\n2. Create your branch (`git checkout -b amazing-feature`)\n3. Make your changes\n4. Add a changeset: `pnpm changeset`\n5. Commit and push\n6. Open a Pull Request\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Contact\n\nBrent Rager\n\n- [Email](mailto:brent@smoo.ai)\n- [LinkedIn](https://www.linkedin.com/in/brentrager/)\n- [BlueSky](https://bsky.app/profile/brentragertech.bsky.social)\n- [TikTok](https://www.tiktok.com/@brentragertech)\n- [Instagram](https://www.instagram.com/brentragertech/)\n\nSmoo Github: [https://github.com/SmooAI](https://github.com/SmooAI)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmooai%2Fconfig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmooai%2Fconfig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmooai%2Fconfig/lists"}