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/document_assess.py
"""Consent-gated input-document structural facts; never emit document content."""
from __future__ import annotations
import argparse
import hashlib
import io
import json
import os
from pathlib import Path
import re
import stat
import subprocess
import sys
import threading
PARSER_VERSION = "6.8.0"
MAX_INPUT = 16 * 1024 * 1024
MAX_PAGES = 200
MAX_SELECTED = 8
MAX_OUTPUT = 8192
MAX_REQUEST = 16384
WALL_SECONDS = 15
FORMATS = {"auto", "pdf", "text", "markdown", "html", "json", "docx", "pptx",
"xlsx", "png", "jpeg"}
class Blocked(ValueError):
"""A public, content-free blocker code."""
def blocked(code):
return {"schema_version": "1.0", "status": "blocked", "assessment": "not-assessed", "code": code,
"service_admission": "not-assessed", "facts": None}
def validate_request(request):
if not isinstance(request, dict) or request.get("approved") is not True:
raise Blocked("inspection-not-approved")
if not {"approved", "path", "sha256"} <= set(request) or set(request) - {
"approved", "path", "sha256", "pages", "whole_document", "format"
}:
raise Blocked("invalid-request")
path, digest, pages = request["path"], request["sha256"], request.get("pages")
if isinstance(path, str) and path.lower().startswith(("http:", "https:", "abfs:", "abfss:")):
raise Blocked("remote-sample-access-not-supported")
if (not isinstance(path, str) or len(path) > 4096 or "\0" in path
or not Path(path).is_absolute()):
raise Blocked("invalid-source-path")
if not isinstance(digest, str) or not re.fullmatch(r"[0-9a-f]{64}", digest):
raise Blocked("invalid-source-identity")
if (pages is not None and (not isinstance(pages, list) or not 1 <= len(pages) <= MAX_SELECTED
or any(type(page) is not int or not 1 <= page <= MAX_PAGES for page in pages)
or len(set(pages)) != len(pages))):
raise Blocked("invalid-page-selection")
if type(request.get("whole_document", False)) is not bool or (
(pages is not None) == request.get("whole_document", False)
):
raise Blocked("explicit-document-scope-required")
if not isinstance(request.get("format", "auto"), str) or request.get("format", "auto") not in FORMATS:
raise Blocked("unsupported-format-hint")
def read_source(request):
path = Path(request["path"])
if sys.platform == "win32":
import ctypes
# Reject device namespaces, UNC, ADS and mapped network drives.
if (str(path).startswith("\\\\") or ":" in str(path)[2:]
or ctypes.windll.kernel32.GetDriveTypeW(str(path.anchor)) not in (3, 6)):
raise Blocked("nonlocal-source")
if any(item.is_symlink() or (
getattr(item.lstat(), "st_file_attributes", 0) & 0x400
) for item in (path, *path.parents)):
raise Blocked("source-link-unsupported")
canonical = path.resolve(strict=True)
with canonical.open("rb") as source:
before = os.fstat(source.fileno())
if not stat.S_ISREG(before.st_mode):
raise Blocked("nonregular-source")
if before.st_size > MAX_INPUT:
raise Blocked("input-limit")
data = source.read(MAX_INPUT + 1)
after = os.fstat(source.fileno())
if len(data) > MAX_INPUT:
raise Blocked("input-limit")
if (before.st_size, before.st_mtime_ns, before.st_ino) != (
after.st_size, after.st_mtime_ns, after.st_ino
) or len(data) != before.st_size:
raise Blocked("source-changed")
if hashlib.sha256(data).hexdigest() != request["sha256"]:
raise Blocked("source-identity-mismatch")
binding = hashlib.sha256(os.path.normcase(str(canonical)).encode("utf-8")).hexdigest()
return data, binding
def deny_document_reads(event, args):
if event in {"open", "os.listdir", "os.scandir"}:
raise PermissionError("Document external read denied")
def assess_bytes(data, selected):
import codecs
import logging
import warnings
try:
import pypdf
except ImportError:
raise Blocked("parser-dependency-missing") from None
if pypdf.__version__ != PARSER_VERSION:
raise Blocked("parser-version-unsupported")
from pypdf.errors import PdfReadError, PdfStreamError
from pypdf.generic import ContentStream
class RejectWarning(logging.Handler):
def emit(self, record):
raise Blocked("pdf-parser-warning")
logger = logging.getLogger("pypdf")
logger.handlers = [RejectWarning()]
logger.propagate = False
logger.setLevel(logging.WARNING)
warnings.simplefilter("error")
for encoding in ("charmap", "utf-16-be", "utf-16-le", "utf-8", "latin-1", "ascii"):
codecs.lookup(encoding)
# Parser imports are trusted installation reads; once bytes are supplied,
# no PDF-directed file read (even local) is permitted.
sys.addaudithook(deny_document_reads)
if not data.startswith(b"%PDF-") or not data.rstrip().endswith(b"%%EOF"):
raise Blocked("invalid-pdf")
try:
reader = pypdf.PdfReader(io.BytesIO(data), strict=True)
if reader.is_encrypted:
raise Blocked("encrypted-pdf")
page_count = len(reader.pages)
if page_count > MAX_PAGES:
raise Blocked("page-limit")
if max(selected) > page_count:
raise Blocked("page-out-of-range")
pages = []
for number in selected:
page = reader.pages[number - 1]
# Direct stream operators, not object inventory or rendered entities.
content = page.get_contents()
operations = ContentStream(content, reader).operations if content is not None else []
images, drawings, forms = 0, 0, 0
for operands, operator in operations:
if operator == b"INLINE IMAGE":
images += 1
elif operator in {b"S", b"s", b"f", b"F", b"f*", b"B", b"B*", b"b", b"b*"}:
drawings += 1
elif operator == b"Do":
obj = page["/Resources"]["/XObject"][operands[0]].get_object()
subtype = obj["/Subtype"]
if subtype == "/Image":
images += 1
elif subtype == "/Form":
forms += 1
else:
raise Blocked("unsupported-paint-object")
# Forms can reference other pages/resources. Do not traverse them to
# estimate modality; report text unknown instead of widening scope.
characters = None if forms else len(page.extract_text())
pages.append({
"page": number,
"text_characters": characters,
"text_available": None if characters is None else characters > 0,
"text_status": "not-assessed-form-content" if forms else "assessed",
"direct_image_paints": images,
"direct_path_paints": drawings,
"form_invocations": forms,
"total_images": None,
"total_drawings": None,
"table_structure": "not-assessed",
"layout_relationships": "not-assessed",
})
return {"page_count": page_count, "pages": pages, "input_profile": "unknown",
"answerability": "not-assessed", "ocr_need": "not-assessed"}
except (PdfReadError, PdfStreamError, KeyError, IndexError, TypeError,
UnicodeError, NotImplementedError):
raise Blocked("pdf-parse-unsupported") from None
except Warning:
raise Blocked("pdf-parser-warning") from None
except PermissionError:
raise Blocked("pdf-external-read-blocked") from None
def dispatch(data, request):
hint = request.get("format", "auto")
if data.startswith(b"%PDF-"):
if hint not in {"auto", "pdf"}:
raise Blocked("format-hint-mismatch")
if request.get("pages") is None:
raise Blocked("pdf-page-selection-required")
return "pdf", f"pypdf=={PARSER_VERSION}", assess_bytes(data, request["pages"])
if request.get("pages") is not None:
raise Blocked("non-pdf-requires-whole-document-scope")
from _document_adapters import AdapterBlocked, assess_document
try:
return assess_document(data, hint, deny_document_reads)
except AdapterBlocked as error:
raise Blocked(str(error)) from None
def worker():
# Isolated mode excludes ambient PYTHONPATH; add only this packaged helper.
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _document_limits import deny_side_effects, install_limits
try:
job_handle = install_limits()
except (OSError, ValueError):
return blocked("worker-limits-unavailable")
sys.addaudithook(deny_side_effects)
binding = {}
try:
raw = sys.stdin.buffer.read(MAX_REQUEST + 1)
if len(raw) > MAX_REQUEST:
raise Blocked("request-limit")
request = json.loads(raw)
validate_request(request)
data, path_digest = read_source(request)
binding = {"source_sha256": request["sha256"], "path_sha256": path_digest}
kind, parser, facts = dispatch(data, request)
return {"schema_version": "1.0", "status": "completed", "assessment": "assessed",
"service_admission": "not-assessed", "format": kind, "parser": parser,
**binding, "facts": facts}
except Blocked as error:
return dict(blocked(str(error)), **binding)
except MemoryError:
return dict(blocked("worker-memory-limit"), **binding)
except RecursionError:
return dict(blocked("document-recursion-limit"), **binding)
except (OSError, ValueError, OverflowError):
return dict(blocked("document-input-or-parse-failed"), **binding)
finally:
# This local deliberately remains live through parsing on Windows.
_ = job_handle
def run_worker(command, request, timeout=WALL_SECONDS):
"""Pipe-only IPC; bounded output reader, no sample or stderr artifacts."""
encoded = json.dumps(request, separators=(",", ":")).encode()
if len(encoded) > MAX_REQUEST:
return blocked("request-limit")
output = bytearray()
exceeded = threading.Event()
io_failed = threading.Event()
with subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL) as process:
def drain():
try:
chunk = process.stdout.read(MAX_OUTPUT + 1)
if len(chunk) > MAX_OUTPUT:
exceeded.set()
process.kill()
else:
output.extend(chunk)
except OSError:
io_failed.set()
def send():
try:
process.stdin.write(encoded)
process.stdin.close()
except OSError:
io_failed.set()
thread = threading.Thread(target=drain, daemon=True)
writer = threading.Thread(target=send, daemon=True)
thread.start()
writer.start()
try:
process.wait(timeout=timeout)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
return blocked("worker-timeout")
finally:
if process.poll() is None:
process.kill()
process.wait()
thread.join()
writer.join()
if exceeded.is_set():
return blocked("worker-output-limit")
if process.returncode not in (0, 2):
return blocked("worker-failed-or-resource-limit")
if io_failed.is_set():
return blocked("worker-io-failed")
try:
result = json.loads(output)
except (ValueError, UnicodeError):
return blocked("worker-invalid-output")
if not isinstance(result, dict) or result.get("status") not in {"completed", "blocked"}:
return blocked("worker-invalid-output")
return result
def assess(request):
try:
validate_request(request)
return run_worker([sys.executable, "-I", "-B", str(Path(__file__).resolve()),
"--worker"], request)
except Blocked as error:
return blocked(str(error))
except OSError:
return blocked("worker-start-failed")
class SafeArgumentParser(argparse.ArgumentParser):
def error(self, message):
raise Blocked("invalid-cli-arguments")
def main():
def private_failure(exc_type, exc_value, traceback):
print(json.dumps(blocked("worker-failed-or-resource-limit")))
# Unexpected parser/runtime failures must not print attacker-controlled
# exception strings or stack traces, including when --worker is invoked.
sys.excepthook = private_failure
if sys.argv[1:] == ["--worker"]:
result = worker()
else:
parser = SafeArgumentParser(description=__doc__)
parser.add_argument("--approve-inspection", action="store_true")
parser.add_argument("--file")
parser.add_argument("--sha256")
parser.add_argument("--pages", help="Explicit 1-based pages, e.g. 1,3; no ranges")
parser.add_argument("--whole-document", action="store_true",
help="Approve whole bounded non-PDF document, not rendered pages")
parser.add_argument("--format", choices=sorted(FORMATS), default="auto")
try:
args = parser.parse_args()
if not args.approve_inspection:
raise Blocked("inspection-not-approved")
pages = None if args.pages is None else [int(value) for value in args.pages.split(",")]
result = assess({"approved": True, "path": args.file,
"sha256": args.sha256, "pages": pages,
"whole_document": args.whole_document, "format": args.format})
except Blocked as error:
result = blocked(str(error))
except ValueError:
result = blocked("invalid-page-selection")
print(json.dumps(result, separators=(",", ":"), ensure_ascii=True))
return 0 if result["status"] == "completed" else 2
if __name__ == "__main__":
raise SystemExit(main())
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