AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Foundry IQ provides a structured framework for creating, diagnosing, and connecting knowledge bases to AI agents. It supports making local or Blob-based documents searchable, managing multi-source knowledge configurations, and retrieving information with citations. The skill emphasizes strict adherence to defined procedures for service discovery, resource creation, and troubleshooting to ensure reliable agent-knowledge integration.
What it does
- Creates searchable knowledge bases from local or Azure Blob storage documents.
- Connects existing knowledge bases to AI agents.
- Diagnoses issues with knowledge base configurations or unsupported connectors.
- Retrieves information from knowledge bases with source citations.
- Manages the lifecycle of search services and knowledge sources.
- Routes requests based on specific operational needs rather than source counts.
When to use it
- When you need to make local or cloud-stored documents searchable by an AI agent.
- When connecting an existing knowledge base to a new or current agent.
- When troubleshooting or diagnosing a knowledge base configuration.
- When you need to create a new search service or knowledge source.
- When performing retrieval tasks that require citations from a knowledge base.
Advantages
- Provides a clear, procedural approach to knowledge base management.
- Ensures consistent handling of multi-source knowledge configurations.
- Includes built-in diagnostic paths for troubleshooting.
- Supports secure, citation-backed retrieval for agent responses.
- Prevents unauthorized or unsupported configuration changes.
Usage examples
- “Create a new knowledge base from my Azure Blob container.”
- The agent will initiate the knowledge base creation procedure, validating the source and setting up the necessary search indexing.
- “Connect my existing knowledge base to the current agent.”
- The agent will follow the connection workflow to link the specified knowledge base to the agent's retrieval pipeline.
- “Why is my multi-source knowledge base failing to index?”
- The agent will trigger the diagnostic procedure to identify configuration drifts or unsupported connector issues.
- “Retrieve information about project timelines from the knowledge base.”
- The agent will query the knowledge base and provide an answer with citations from the source documents.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/microsoft/foundry-iq/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip foundry-iq.zip -d .agents/skills
Documentation by Microsoft
Foundry IQ
Read one procedure before questions/actions; invocation is not a read.
Read the owning procedure before blocked/unsupported responses too.
Before mutation plans/approval, successfully read its required pre-action references, selected
branches only. Do not reload successful reads. On failure, try only permitted
bounded exact-path reads with any supported reader; never bypass restrictions
or search broadly. If still unavailable: blocked: reference-unavailable, name
missing references and inability to plan. Never invent requirements/plans.
Failures first.
Cleanup and receipt-backed execution go directly to their lifecycle/producer owner; do not reopen Search intake, provisioning or hardening.
Before expensive service discovery, reuse supplied resource/intent; otherwise ask one early USE EXISTING / FIND CANDIDATES / CREATE NEW choice. Only FIND enumerates; supplied identity uses exact/minimum scoped resolution. CREATE checks its proposed name, not existing-service inventories. Preserve these answers across source/KB/CU/model handoffs; selection is not write approval.
Searchable docs: KB + validated retrieval. Confirm intent once; KS-only must be explicit. Child success is not KB completion. Unclear/compound/mode/completion: read.
Route by requested operation, not existing KB source count. Connecting an existing KB with two or more sources, without changing the KB, uses Connect. Read-only operations use their owning procedure and actual helper constraints; this does not add retrieval modes or supported source kinds. Explicit unsupported provisioning or multi-source KB creation/reconfiguration uses Diagnose and stops before discovery, even when connecting an agent is also requested. This routing takes precedence over classic-search terms (e.g. hybrid search) in compound requests. Never end in a plain refusal: Diagnose gives the boundary, docs pointer and agent handoff; writes still need an approved concrete plan. Do not silently execute only the supported part of a compound request. If existing-KB connection versus KB creation/reconfiguration is unclear, read intent-routing and clarify that scope before Azure discovery. Never infer KB mutation.
| Outcome | Read |
|---|---|
| Cleanup | Plan cleanup |
| Failure/drift | Diagnose |
| Unsupported connector provisioning / multi-source KB creation or reconfiguration | Diagnose |
| Connect | Connect |
| Read KB | Query |
| Search only | Search |
| File KS only | File |
| Blob/ADLS KS only | Blob |
| Searchable/KB | KB |
Generic agents: microsoft-foundry.
Reads: no approval; approve unchanged plans before writes.
Hide hashes. No Search/Storage keys, scope widening, guessed identity/boundaries,
drift repair or joint cleanup/creation approval. Acceptance != success.
Files
- ATTRIBUTION.mdAdded by AutoGineer977 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md3.7 KiB
- agents/connect-hosted-toolbox.md7.8 KiB
- agents/connect-hosted.md7.8 KiB
- agents/connect-prompt-sdk-fallback.md7.8 KiB
- agents/connect.md7.8 KiB
- agents/create-missing-agent.md7.8 KiB
- helpers/_blob_observation.pyScript4.4 KiB
- helpers/_blob_source_read.pyScript39.5 KiB
- helpers/_bootstrap_io.pyScript30.1 KiB
- helpers/_cleanup_dependencies.pyScript27.5 KiB
- helpers/_cleanup_receipts.pyScript13.5 KiB
- helpers/_common.pyScript36.2 KiB
- helpers/_document_adapters.pyScript15.0 KiB
- helpers/_document_limits.pyScript3.9 KiB
- helpers/_embedding.pyScript7.0 KiB
- helpers/_file_inventory.pyScript24.4 KiB
- helpers/_file_source_config.pyScript15.6 KiB
- helpers/_indexer_observation.pyScript7.1 KiB
- helpers/_initial_prompt.pyScript12.5 KiB
- helpers/_private_json.pyScript2.4 KiB
- helpers/_progress.pyScript12.1 KiB
- helpers/_prompt_read.pyScript17.7 KiB
- helpers/_search_read.pyScript6.0 KiB
- helpers/_source_readback.pyScript1.6 KiB
- helpers/blob-contracts.md7.8 KiB
- helpers/blob-cu-contracts.md7.8 KiB
- helpers/blob_inventory.pyScript17.1 KiB
- helpers/blob_recheck.pyScript64.6 KiB
- helpers/blob_source.pyScript35.8 KiB
- helpers/bootstrap-contracts.md7.8 KiB
- helpers/bootstrap_azure.pyScript41.5 KiB
- helpers/cleanup_plan.pyScript41.4 KiB
- helpers/contracts.md7.8 KiB
- helpers/cu_ingestion_auth.pyScript12.5 KiB
- helpers/document-assessment.md7.8 KiB
- helpers/document_assess.pyScript14.0 KiB
- helpers/file-upload-recovery.md7.8 KiB
- helpers/file_cu_canary.pyScript32.7 KiB
- helpers/file_cu_mi.pyScript9.6 KiB
- helpers/file_ingest.pyScript15.4 KiB
- helpers/file_source.pyScript31.7 KiB
- helpers/file_upload.pyScript53.7 KiB
- helpers/hosted_connect.pyScript30.8 KiB
- helpers/kb-contracts.md7.8 KiB
- helpers/knowledge_base_retrieve.pyScript7.7 KiB
- helpers/model-discovery-contracts.md7.8 KiB
- helpers/model-discovery-scopes.md7.8 KiB
- helpers/model_discovery.pyScript23.7 KiB
- helpers/private-artifacts.md7.2 KiB
- helpers/private_artifacts.pyScript4.8 KiB
- helpers/prompt_cleanup.pyScript22.0 KiB
- helpers/prompt_connect.pyScript62.3 KiB
- helpers/requirements-assessment.txt103 B
- helpers/retrieval-verification-contracts.md7.8 KiB
- helpers/retrieval_verify.pyScript19.6 KiB
- helpers/search-intake-contracts.md7.6 KiB
- helpers/search_intake.pyScript18.4 KiB
- helpers/search_reconcile.pyScript59.7 KiB
- helpers/source_vector.pyScript33.2 KiB
- helpers/throttle-recovery.md5.0 KiB
- helpers/vector-contracts.md7.8 KiB
- knowledge-bases/create.md8.1 KiB
- knowledge-bases/retrieve.md7.8 KiB
- knowledge-sources/create-azure-blob.md7.8 KiB
- knowledge-sources/create-file.md7.8 KiB
- lifecycle/cleanup.md7.8 KiB
- references/abstention.md1.0 KiB
- references/blob-binding-evidence.md7.8 KiB
- references/blob-indexer-observation.md7.7 KiB
- references/blob-ingestion-progress.md6.5 KiB
- references/blob-readiness-recheck.md7.8 KiB
- references/blob-vector-readiness.md2.6 KiB
- references/bootstrap-azure.md7.8 KiB
- references/content-fit.md7.8 KiB
- references/cu-ingestion.md7.8 KiB
- references/file-cu-canary.md7.8 KiB
- references/intent-routing.md7.7 KiB
- references/owner.md2.1 KiB
- references/platform-contracts.md7.7 KiB
- references/platform-interfaces.md7.8 KiB
- references/resource-intake.md7.8 KiB
- references/search-substrate.md7.8 KiB
- references/standard-cu.md7.8 KiB
- search-services/create.md7.8 KiB
- troubleshooting/diagnose.md8.7 KiB
helpers/_progress.py
"""Bounded, content-free observations; never a service execution controller."""
from __future__ import annotations
from functools import wraps
from contextlib import contextmanager
import copy
from datetime import datetime
import json
import math
import os
import sys
import time
import threading
try:
from ._common import HelperFailure
except ImportError:
from _common import HelperFailure
STAGES = {
"file-source": ("validation", "source-reconciliation", "file-inventory", "file-upload", "file-readback"),
"file-upload": ("file-inventory", "file-upload", "file-readback"),
"blob-source": ("validation", "blob-inventory", "source-reconciliation", "ingestion-cycle",
"blob-readback", "source-readback"),
"blob-monitor": ("ingestion-cycle",),
"blob-capture": ("evidence-validation", "context-check", "source-binding", "blob-inventory", "checkpoint"),
"blob-recheck": ("evidence-validation", "context-check", "source-binding", "blob-inventory",
"ingestion-cycle", "blob-readback", "source-readback", "context-readback"),
"search-bootstrap": ("validation", "context-check", "region-check", "absence-check", "search-submit",
"arm-wait", "arm-readback"),
}
COUNTS = frozenset(("uploads_acknowledged", "files_reused", "files_verified",
"status_checks", "cycle_updates_processed", "cycle_items_skipped",
"files_failed", "files_unverified", "files_not_attempted", "files_pending", "files_ingested"))
FILE_HEARTBEAT_SECONDS = 5
IO_WARNING = "progress-output-failed: stderr progress could not be written; execution result is authoritative."
SHUTDOWN_WARNING = "progress-shutdown-flush-unresolved: failed stderr could not be redirected; shutdown may override the exit code."
def validate_blob_progress(value):
fields = {"schema_version", "phase", "run_start", "processed", "failed", "skipped",
"unit", "total", "remaining", "denominator", "synchronization_status",
"elapsed_seconds", "next_check_seconds"}
if not isinstance(value, dict) or set(value) != fields:
raise ValueError("Invalid Blob progress shape.")
if (value["schema_version"] != "1.0" or value["unit"] != "item-updates"
or value["denominator"] != "not-comparable-to-files"
or value["total"] is not None or value["remaining"] is not None
or value["phase"] not in ("ingesting", "waiting", "throttled", "paused", "completed", "failed")
or value["synchronization_status"] not in ("not-reported", "active", "creating", "deleting")):
raise ValueError("Invalid Blob progress labels.")
for field in ("processed", "failed", "skipped"):
count = value[field]
if count is not None and (type(count) is not int or count < 0):
raise ValueError("Invalid Blob progress count.")
for field in ("elapsed_seconds", "next_check_seconds"):
number = value[field]
if field == "next_check_seconds" and number is None:
continue
if type(number) not in (int, float) or not math.isfinite(number) or number < 0:
raise ValueError("Invalid Blob progress timing.")
if value["next_check_seconds"] is not None and value["next_check_seconds"] > 60:
raise ValueError("Invalid Blob progress wait.")
start = value["run_start"]
if start is not None:
if not isinstance(start, str) or len(start) > 40:
raise ValueError("Invalid Blob progress run.")
parsed = datetime.fromisoformat(start.replace("Z", "+00:00"))
if parsed.tzinfo is None or parsed.isoformat() != start:
raise ValueError("Blob progress run must be a canonical timestamp.")
class Progress:
def __init__(self, workflow, *, enabled=True, stream=None, clock=time.monotonic):
self.stages = STAGES[workflow]
self.workflow = workflow
self.enabled = enabled
self.stream = stream
self.clock = clock
self.depth = 0
self.stage = self.stages[0]
self.counts = {}
self.started = None
self.elapsed = 0.0
self.last_sent = None
self.last_stage = None
self.output_failed = False
self.shutdown_flush_unresolved = False
self.blob_progress = None
self.last_blob_phase = None
def blob_update(self, value):
if not self.workflow.startswith("blob-"):
raise ValueError("Blob progress cannot describe a File or ARM workflow.")
validate_blob_progress(value)
self.blob_progress = copy.deepcopy(value)
for field, target in (("processed", "cycle_updates_processed"), ("skipped", "cycle_items_skipped")):
self.counts.pop(target, None)
if value[field] is not None:
self.counts[target] = value[field]
self.update("ingestion-cycle")
def update(self, stage, **counts):
if stage not in self.stages or self.stages.index(stage) < self.stages.index(self.stage):
raise ValueError("Invalid progress stage transition.")
if any(key not in COUNTS or type(value) is not int or value < 0 for key, value in counts.items()):
raise ValueError("Invalid progress count.")
self.stage = stage
self.counts.update(counts)
self._emit("running")
def waiting(self, seconds):
if not isinstance(seconds, (int, float)) or not math.isfinite(seconds) or not 0 <= seconds <= 30:
raise ValueError("Invalid recovery wait.")
self._emit("waiting", wait={"reason": "http-429", "seconds": seconds})
@contextmanager
def processing_file(self, ordinal, total, attempt):
if (self.workflow not in {"file-source", "file-upload"} or type(ordinal) is not int
or type(total) is not int or not 1 <= ordinal <= total <= 200 or attempt not in (1, 2)):
raise ValueError("Invalid active file.")
active = {"ordinal": ordinal, "total": total, "attempt": attempt}
if not self.enabled or self.output_failed:
yield
return
started = self.clock()
stop = threading.Event()
def pulse():
while not stop.wait(FILE_HEARTBEAT_SECONDS):
if self.output_failed:
return
self._emit("processing", active=active, active_started=started)
self._emit("processing", active=active, active_started=started)
worker = threading.Thread(target=pulse, name="foundry-file-progress", daemon=True)
worker.start()
try:
yield
finally:
stop.set()
worker.join()
def _emit(self, state, *, wait=None, active=None, active_started=None):
if not self.enabled or self.output_failed:
return
observed = self.clock()
# Clock regressions/nonfinite observations must not create negative time
# or bypass throttling. Progress never shares the service deadline clock.
if math.isfinite(observed):
if self.started is None:
self.started = observed
delta = observed - self.started
if math.isfinite(delta):
self.elapsed = max(self.elapsed, delta)
phase = self.blob_progress["phase"] if self.blob_progress is not None else None
if (state == "running" and self.stage == self.last_stage and phase == self.last_blob_phase
and self.last_sent is not None and self.elapsed - self.last_sent < 1.0):
return
event = {
"event": "progress", "workflow": self.workflow, "activity": self.stage,
"state": state, "elapsed_seconds": round(self.elapsed, 3),
"remaining_checks": [] if state == "completed" else list(self.stages[self.stages.index(self.stage) + 1:]),
}
if self.counts:
event["completed_counts"] = dict(self.counts)
if wait is not None:
event["wait"] = wait
if active is not None:
duration = observed - active_started
event["processing_file"] = {**active, "elapsed_seconds": round(max(0, duration), 3) if math.isfinite(duration) else 0}
if self.blob_progress is not None:
value = self.blob_progress
event["blob_progress"] = copy.deepcopy(value)
counts = "; ".join(f"{field}={value[field] if value[field] is not None else 'unknown'}"
for field in ("processed", "failed", "skipped"))
next_check = ("paused/resumable" if value["phase"] == "paused" else "none") if value["next_check_seconds"] is None else f"{value['next_check_seconds']:g}s"
event["message"] = (
f"Blob ingestion observation {value['phase']}: item updates {counts}; file total/remaining unknown "
f"(not comparable); elapsed={value['elapsed_seconds']:g}s; next check={next_check}."
)
stream = self.stream if self.stream is not None else sys.stderr
try:
text = json.dumps(event, sort_keys=True, separators=(",", ":")) + "\n"
if stream.write(text) != len(text):
raise OSError("Short progress write.")
stream.flush()
except (OSError, UnicodeError, ValueError):
# Continue the approved operation, retaining a fixed secondary warning
# even when stderr itself is broken. Never replace a primary failure.
self.output_failed = True
self._disable_failed_default_stderr(stream)
self.last_sent, self.last_stage = self.elapsed, self.stage
self.last_blob_phase = phase
def _disable_failed_default_stderr(self, stream):
if self.stream is not None or stream is not sys.__stderr__ or stream.closed:
return
try:
if stream.fileno() == 2:
# A failed TextIOWrapper flush can retain pending bytes. Redirect
# only the failed native stderr so shutdown can drain that buffer
# without replacing the authoritative process exit status.
sink = os.open(os.devnull, os.O_WRONLY)
try:
os.dup2(sink, 2)
finally:
if sink != 2:
os.close(sink)
except (OSError, ValueError):
self.shutdown_flush_unresolved = True
def finish(self, result=None, failure=None):
if self.blob_progress is not None and failure is not None:
self.blob_progress.update(phase="failed", next_check_seconds=None)
if failure is not None:
state = "partial" if failure.partial or failure.writes else "blocked"
else:
state = {"verified": "completed", "unverified": "blocked"}.get(result["status"], result["status"])
if state not in {"completed", "blocked", "partial"}:
raise ValueError("Invalid progress terminal state.")
self._emit(state)
if self.output_failed:
warnings = failure.warnings if failure is not None else result.setdefault("warnings", [])
if IO_WARNING not in warnings:
warnings.append(IO_WARNING)
if self.shutdown_flush_unresolved and SHUTDOWN_WARNING not in warnings:
warnings.append(SHUTDOWN_WARNING)
def reporting(workflow):
"""One reporter and terminal event across nested public entrypoints."""
def decorate(function):
@wraps(function)
def wrapped(*args, progress=None, **kwargs):
if progress is None:
progress = Progress(workflow, enabled=False)
outer = progress.depth == 0
progress.depth += 1
try:
result = function(*args, progress=progress, **kwargs)
except HelperFailure as failure:
if outer:
progress.finish(failure=failure)
raise
else:
if outer:
progress.finish(result=result)
return result
finally:
progress.depth -= 1
return wrapped
return decorate
def add_progress_argument(parser):
parser.add_argument("--no-progress", dest="progress", action="store_false",
help="Suppress content-free execution progress on stderr.")
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
The author says: Azure
Security
What our scanner noticed· Medium risk
- References to credential files
- Instructions that use the network
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Microsoft
- Publisher
- Microsoft (Official)
- Source
- microsoft/skills · .github/plugins/foundry-iq-skills/skills/foundry-iq · commit 0696600
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from .github/plugins/foundry-iq-skills/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Microsoft.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download foundry-iq.zip