Install
$ agentstack add skill-nebulavenus-forge-gpu-forge-import-settings-editor ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
forge-import-settings-editor
Add per-asset import settings to a pipeline web UI. Assets get individual .import.toml sidecar files that override global config, and a browser-based editor form renders type-specific controls for each setting.
When to use this skill
- Adding per-asset configuration overrides to a processing pipeline
- Building a settings editor form driven by a schema definition
- Implementing three-layer settings merge (defaults → global → per-item)
- Adding TOML sidecar file I/O without a third-party TOML writer
- Triggering single-item re-processing from a web UI
Key functions and endpoints
| Component | Function / Route | Purpose | |---|---|---| | import_settings.py | sidecar_path(source) | Return .import.toml path for a source file | | import_settings.py | load_sidecar(source) | Parse sidecar TOML, empty dict if missing | | import_settings.py | save_sidecar(source, settings) | Write settings to sidecar file | | import_settings.py | delete_sidecar(source) | Remove sidecar (revert to defaults) | | import_settings.py | merge_settings(global, per_asset) | Two-layer overlay merge | | import_settings.py | get_effective_settings(plugin, global, per_asset) | Three-layer merge with schema defaults | | import_settings.py | get_schema(plugin_name) | Return schema dict for a plugin type | | server.py | GET /api/assets/{id}/settings | Read schema + global + per-asset + effective | | server.py | PUT /api/assets/{id}/settings | Save per-asset overrides as .import.toml | | server.py | DELETE /api/assets/{id}/settings | Remove sidecar (revert to defaults) | | server.py | POST /api/assets/{id}/process | Re-process with effective settings |
Architecture
Three-layer settings merge:
Schema Defaults ──> Global Config (pipeline.toml) ──> Per-Asset (.import.toml)
│ │ │
└──────────────────────┴──────────────────────────────┘
│
get_effective_settings()
│
Effective Settings
Each layer overrides the previous. get_effective_settings() starts with schema defaults, overlays global settings, then per-asset overrides.
Correct order
Backend
- Define settings schemas in
import_settings.py— one dict per plugin type
with type, label, description, default, and optional constraints
- Implement sidecar CRUD —
sidecar_path,load_sidecar,save_sidecar,
delete_sidecar
- Implement merge functions —
merge_settings,get_effective_settings - Add API endpoints to
server.py— GET, PUT, DELETE for settings, POST for
process
- Integrate sidecars into CLI processing — load sidecars in
_process_files(),
include settings in fingerprint cache key
Frontend
- Add TypeScript types for
ImportSettingsResponse,SettingsSchemaField,
ProcessResponse in api.ts
- Add API functions —
fetchImportSettings,saveImportSettings,
deleteImportSettings, processAsset
- Add UI primitives —
Label,Select,Switch,Separatorin
components/ui/
- Build
ImportSettingscomponent with schema-driven form rendering - Mount on the asset detail page below the preview panel
- Wire TanStack Query cache invalidation on mutations
Settings schema definition
Each plugin type has a schema dict describing its configurable fields:
TEXTURE_SETTINGS_SCHEMA: dict[str, dict] = {
"max_size": {
"type": "int", # Control type: bool, int, float, str, list[float]
"label": "Max size", # Human-readable label
"description": "Clamp width and height to this limit (pixels).",
"default": 2048, # Schema default value
"min": 1, # Optional: numeric minimum
"max": 8192, # Optional: numeric maximum
},
"compression": {
"type": "str",
"label": "GPU compression",
"description": "GPU block-compression codec.",
"default": "none",
"options": ["none", "basisu", "astc"], # Optional: enum values
},
"normal_map": {
"type": "bool",
"label": "Normal map",
"description": "Treat as a normal map (BC5, linear color space).",
"default": False,
},
}
SETTINGS_SCHEMAS: dict[str, dict[str, dict]] = {
"texture": TEXTURE_SETTINGS_SCHEMA,
"mesh": MESH_SETTINGS_SCHEMA,
}
TOML sidecar format
Sidecars are flat key-value TOML files. Only overridden keys are present:
normal_map = true
compression = "basisu"
basisu_quality = 200
Write TOML with string formatting — no third-party serializer needed for flat tables. Check isinstance(value, bool) before isinstance(value, int) since bool is a subclass of int in Python.
Frontend control mapping
| Schema type | UI control | Notes | |---|---|---| | bool | Switch toggle | onCheckedChange callback | | str with options | Select dropdown | Renders ` per entry | | int | Input type="number" | Uses min/max from schema | | float | Input type="number" | step={0.01} | | list[float] | Input type="text"` | Comma-separated, parsed on change |
Common mistakes
- Forgetting bool-before-int check in TOML formatting. Python's
boolis
a subclass of int, so isinstance(True, int) is True. Always check isinstance(value, bool) first.
- Not including settings in the fingerprint cache key. If only the content
hash is cached, changing a sidecar does not trigger reprocessing. Combine the content hash with a JSON digest of the merged settings.
- Mutating the global settings dict during merge.
merge_settings()must
return a new dict — never .update() the input.
- Not invalidating the right TanStack Query keys. After processing, both
["asset", id] and ["assets"] (list) must be invalidated so the status badge and preview update.
- Missing error handling for malformed sidecars.
load_sidecar()should
catch TOMLDecodeError and raise a clear ValueError. The CLI should log a warning and fall back to global settings; the API should return 400.
Ready-to-use template
import_settings.py — core pattern
from pathlib import Path
import tomllib
SIDECAR_SUFFIX = ".import.toml"
def sidecar_path(source: Path) -> Path:
return source.parent / (source.name + SIDECAR_SUFFIX)
def load_sidecar(source: Path) -> dict:
path = sidecar_path(source)
if not path.is_file():
return {}
try:
with path.open("rb") as f:
return tomllib.load(f)
except tomllib.TOMLDecodeError as exc:
raise ValueError(f"Malformed sidecar {path}: {exc}") from exc
def get_effective_settings(plugin_name: str, global_s: dict, per_asset: dict) -> dict:
schema = SETTINGS_SCHEMAS.get(plugin_name, {})
result = {key: spec["default"] for key, spec in schema.items()}
result.update(global_s)
result.update(per_asset)
return result
API endpoint pattern
@app.get("/api/assets/{asset_id}/settings")
async def get_import_settings(asset_id: str):
asset = _get_cached_asset(asset_id)
plugin_name = _plugin_name_for_type(asset.asset_type)
schema = get_schema(plugin_name)
global_settings = config.plugin_settings.get(plugin_name, {})
per_asset = load_sidecar(Path(asset.source_path))
effective = get_effective_settings(plugin_name, global_settings, per_asset)
return {
"schema_fields": schema,
"global_settings": global_settings,
"per_asset": per_asset,
"effective": effective,
"has_overrides": bool(per_asset),
}
React component pattern
const { data: settings } = useQuery({
queryKey: ["settings", assetId],
queryFn: () => fetchImportSettings(assetId),
})
const saveMutation = useMutation({
mutationFn: (overrides) => saveImportSettings(assetId, overrides),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["settings", assetId] })
},
})
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Nebulavenus
- Source: Nebulavenus/forge-gpu
- License: Zlib
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.