# Quickstart

> Scaffold a profile, validate it, and run your first scan.

Source: https://refpoint.dev/docs/getting-started/quickstart

This page takes you from an empty directory to a saved JSON result you can
re-render, diff, and file as evidence. It should take about ten minutes.

## Scaffold a profile

```shell
refpoint init my-baseline --title "My Baseline" --author "Platform Team"
```

That writes a profile root and one example control:

```
my-baseline/
├── profile.rpp
└── controls/
    └── example.rpc
```

`profile.rpp` carries a commented `allowed_commands` hint. Without it, the
first `command` check anyone adds is refused with no obvious cause.

## Write a control

Open `my-baseline/controls/example.rpc` and replace the example with something
you actually care about.

```hcl
control "ssh-01" {
  title       = "SSH root login is disabled"
  description = "Direct root login over SSH removes accountability."
  impact      = 0.9
  remediation = "Set PermitRootLogin no in /etc/ssh/sshd_config and reload sshd."

  platform = ["linux"]

  tags = {
    category = "ssh"
  }

  only_if "package" {
    name      = "openssh-server"
    installed = true
  }

  check "root-login" "sshd_config" {
    option "PermitRootLogin" {
      value = "no"
    }
  }
}
```

The `only_if` block is a precondition. On a host with no SSH server the control
is reported as `skipped` with a reason, rather than failing for a service that
was never meant to be there.

## Validate before you run

```shell
refpoint check my-baseline
```

`check` parses the profile and decodes every check body, `only_if`
precondition, and `any_of` member against its resource provider. It collects
every problem in one pass instead of stopping at the first, and each finding
renders with a clickable `path:line:col` and a "did you mean" suggestion.

It also reports which executables the profile's `command` checks would run:

```
Profile "my-baseline" is valid (12 controls loaded)
Commands used:     getent, systemctl
Declares no allowed_commands, so the operator's list governs alone.
Run with: --allowed-commands getent,systemctl
```

## Run it

```shell
refpoint run my-baseline
```

With no target given, the run defaults to `local`. Every run prints a
three-line banner to stderr before anything else:

```
refpoint <version>
config loaded: <absolute path or "none">
profiles run: <absolute path>
```

That goes to stderr, not stdout, so a report streaming to stdout is never
contaminated. The config path is announced because the working directory is
searched first, and a `config.toml` shipped inside a cloned repository would
otherwise govern the run silently.

## Preview a fleet run first

```shell
refpoint run my-baseline --targets web-01,web-02 --dry-run
```

The dry run opens transports, probes each target's platform, and classifies
every control as `run`, `waive`, or `skip` with a reason. It executes no checks
and always exits 0. Controls guarded by `only_if` are marked conditional, since
the precondition is decided on the target at run time.

## Save the result and work with it

```shell
refpoint run my-baseline --format json --output result.json
refpoint report result.json --format html --output report.html
refpoint tui result.json
refpoint diff last-week.json result.json
```

The JSON file is the artifact of record. Re-renderings produced by `report` are
derivative and are not attested.

## Read the exit code

| Code | Condition |
|------|-----------|
| 0 | Everything passed |
| 1 | At least one control failed, and either no threshold was set or the score met it |
| 2 | At least one target was unreachable or a control errored |
| 5 | Controls failed and the weighted score fell below `--threshold` |
| 130 | Interrupted by SIGINT or SIGTERM |

Code 2 is the one to watch in CI. It means the scan could not see part of what
it was asked to look at, which is a broken run rather than a fleet to
remediate. Unreachable targets are counted separately and are never pruned from
the report, so a job that reached only half its hosts can never report a clean
pass.