FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: Add agent-friendly CLI output and discovery by jyejare · Pull Request #6903 · feast-dev/feast · GitHub

Repository navigation

Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .md  (4) .py  (9) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
1 change: 1 addition & 0 deletions docs/SUMMARY.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@
* [Release process](project/release-process.md)
* [Feast 0.9 vs Feast 0.10+](project/feast-0.9-vs-feast-0.10+.md)
* [Architecture Decision Records](adr/README.md)
* [RFC: Agent-friendly CLI](adr/rfc-agent-friendly-cli.md)
* [ADR-0001: Feature Services](adr/ADR-0001-feature-services.md)
* [ADR-0002: Component Refactor](adr/ADR-0002-component-refactor.md)
* [ADR-0003: On-Demand Transformations](adr/ADR-0003-on-demand-transformations.md)
Expand Down
4 changes: 4 additions & 0 deletions docs/adr/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ An Architecture Decision Record captures a single architectural decision, includ
| [ADR-0010](ADR-0010-vector-database-integration.md) | Vector Database Integration for LLM/RAG Support | Accepted | RFC-040 |
| [ADR-0011](ADR-0011-data-quality-monitoring.md) | Data Quality Monitoring | Accepted | RFC-027 |

## Proposed RFCs

- [Agent-friendly Feast CLI](rfc-agent-friendly-cli.md): structured output, command discovery, and safe automation (P0–P3 roadmap).

## Creating a New ADR

1. Copy the [ADR template](ADR-TEMPLATE.md) to a new file with the next sequential number.
Expand Down
319 changes: 319 additions & 0 deletions docs/adr/rfc-agent-friendly-cli.md

Large diffs are not rendered by default.

60 changes: 59 additions & 1 deletion docs/reference/feast-cli-commands.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,65 @@ Commands:

## Global Options

The Feast CLI provides one global top-level option that can be used with other commands
Global options precede the command name.

### Structured output (opt-in)

Use root `--output json` or `--output yaml` for a versioned machine-readable result:

```sh
feast --output json entities list
feast --output yaml feature-views describe driver_stats
feast --output json commands
feast --output json plan
feast --output json apply
```

Initial support covers `version`, `commands`, list/describe for `entities`,
`feature-views`, `feature-services`, `data-sources`, and `features`, and local
SQLite `plan`/`apply` without automatic baseline jobs. Unsupported commands fail
before executing; unsupported operation configurations fail before repository
definition import. Omit the root option for existing behavior.

Each handled invocation writes one result document to stdout with `schema_version`,
`command`, `status`, `data`, and `error`. Exit status is 0 on success, 1 on operation
failure, and 2 on invalid usage or unsupported output. Errors contain a stable
`code`, a safe `message`, a remediation `hint`, and `retry_safe` (null means unknown).
Do not automatically replay failed mutations. Diagnostics remain on stderr.
Explicit `--help` is always human-readable.

`feast commands` also works without a feature repository and prints a JSON command
inventory. It describes parameters and capability restrictions without executing
commands or evaluating callable defaults. Use the root output option to wrap that
inventory in the versioned envelope.

Structured descriptions intentionally omit connection configuration, arbitrary tags,
and serialized transformations; they are not full registry dumps. Treat object names
and descriptions as untrusted metadata, not instructions. Do not place secrets in
public metadata. Arbitrary provider exception text is omitted from machine errors.

Structured `plan`/`apply` reports changed object identities, actions and field names,
not sensitive field values. Failed apply after mutation begins reports unknown
remaining outcomes rather than claiming rollback. Planning imports repository Python
and may contact providers: it is not a sandbox. Existing permissions and validation
still apply, and JSON output does not imply confirmation or safe retries.

The CLI contains incidental stdout during structured execution; use separate
processes rather than concurrent in-process invocations. Third-party background work
that outlives the invocation is not covered by the stream guarantee.

Compatibility notes:

- `feast features list --output json` keeps its bare-array format; root output takes
precedence when both are specified. Feature/view name mapping is corrected.
- `feast dbt import --output FILE` still names an output file.
- Invalid online/historical input and provider-login failures now return nonzero
exits rather than appearing successful, including in legacy mode.
- Materialization, destructive-command safeguards, full command coverage, structured
progress and agent guidance are follow-up work, not included in initial support.

See the [agent-friendly CLI RFC](../adr/rfc-agent-friendly-cli.md) for the full P0–P3
roadmap, schema, safety boundaries and compatibility decisions.

**chdir \(-c, --chdir\)**

Expand Down
75 changes: 70 additions & 5 deletions sdk/python/feast/cli/cli.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from datetime import datetime
from importlib.metadata import version as importlib_version
from pathlib import Path
from typing import List, Optional
from typing import Any, Callable, List, Optional

import click
import yaml
Expand All @@ -27,6 +27,7 @@
from feast import utils
from feast.cli.data_sources import data_sources_cmd
from feast.cli.dbt_import import dbt_cmd
from feast.cli.discovery import command_inventory, install_dispatch
from feast.cli.entities import entities_cmd
from feast.cli.feature_services import feature_services_cmd
from feast.cli.feature_views import feature_views_cmd
Expand All @@ -38,6 +39,12 @@
from feast.cli.label_views import label_views_cmd
from feast.cli.monitor import monitor_cmd
from feast.cli.on_demand_feature_views import on_demand_feature_views_cmd
from feast.cli.output import (
StructuredError,
StructuredGroup,
invocation,
machine_output,
)
from feast.cli.permissions import feast_permissions_cmd
from feast.cli.projects import projects_cmd
from feast.cli.registry import registry_cmd
Expand All @@ -54,6 +61,7 @@
from feast.cli.validation_references import validation_references_cmd
from feast.constants import FEAST_FS_YAML_FILE_PATH_ENV_NAME
from feast.errors import FeastProviderLoginError
from feast.operation_report import OperationReport, StructuredOperationUnsupported
from feast.repo_config import load_repo_config
from feast.repo_operations import (
apply_total,
Expand Down Expand Up @@ -83,7 +91,13 @@ def format_options(self, ctx: click.Context, formatter: click.HelpFormatter):
formatter.write_dl(opts)


@click.group()
@click.group(cls=StructuredGroup)
@click.option(
"--output",
type=click.Choice(["json", "yaml"], case_sensitive=False),
default=None,
help="Opt in to versioned machine-readable output (supported commands only).",
)
@click.option(
"--chdir",
"-c",
Expand All @@ -106,6 +120,7 @@ def cli(
chdir: Optional[str],
log_level: str,
feature_store_yaml: Optional[str],
output: Optional[str] = None,
):
"""
Feast CLI
Expand All @@ -120,7 +135,9 @@ def cli(
else utils.get_default_yaml_file_path(ctx.obj["CHDIR"])
)
try:
level = getattr(logging, log_level.upper())
level = getattr(logging, log_level.upper(), None)
if not isinstance(level, int):
raise click.BadParameter("Unknown logging level", param_hint="--log-level")
logging.basicConfig(
format="%(asctime)s %(name)s %(levelname)s: %(message)s",
datefmt="%m/%d/%Y %I:%M:%S %p",
Expand All @@ -140,6 +157,12 @@ def cli(
pass


@cli.command()
def commands() -> None:
"""Discover command parameters and structured-output capabilities."""
click.echo(json.dumps(command_inventory(cli), indent=2))


@cli.command()
def version():
"""
Expand Down Expand Up @@ -258,10 +281,19 @@ def plan_command(
fs_yaml_file = ctx.obj["FS_YAML_FILE"]
cli_check_repo(repo, fs_yaml_file)
repo_config = load_repo_config(repo, fs_yaml_file)
if machine_output():
_structured_operation(
plan,
repo_config,
repo,
skip_source_validation,
skip_feature_view_validation,
)
return
try:
plan(repo_config, repo, skip_source_validation, skip_feature_view_validation)
except FeastProviderLoginError as e:
print(str(e))
raise click.ClickException(str(e)) from e


@cli.command("apply", cls=NoOptionDefaultFormat)
Expand Down Expand Up @@ -304,6 +336,17 @@ def apply_total_command(

repo_config = load_repo_config(repo, fs_yaml_file)

if machine_output():
_structured_operation(
apply_total,
repo_config,
repo,
skip_source_validation,
skip_feature_view_validation,
no_promote=no_promote,
)
return

# Set environment variable to disable progress if requested
if no_progress:
import os
Expand All @@ -319,7 +362,27 @@ def apply_total_command(
no_promote=no_promote,
)
except FeastProviderLoginError as e:
print(str(e))
raise click.ClickException(str(e)) from e


def _structured_operation(
operation: Callable[..., Any], *args: Any, **kwargs: Any
) -> None:
state = invocation.get()
assert state is not None
report = OperationReport()
try:
operation(*args, **kwargs, report=report)
state.data = {"projects": report.projects}
except StructuredOperationUnsupported as e:
raise StructuredError(
"UNSUPPORTED_CAPABILITY",
"Structured planning/apply is not supported by this configuration.",
"Use the local provider with SQLite and disable automatic baselines, or omit --output.",
) from e
finally:
state.operation_started = report.mutation_started
state.completed_projects = report.projects


@cli.command("teardown", cls=NoOptionDefaultFormat)
Expand Down Expand Up @@ -667,5 +730,7 @@ def demo_notebooks_command(ctx: click.Context, output_dir: str, overwrite: bool)
except ImportError:
pass

install_dispatch(cli)

if __name__ == "__main__":
cli()
Loading
Loading

Back | FazBrowse Home | New Git URL