diff --git a/.arcconfig b/.arcconfig
new file mode 100644
--- /dev/null
+++ b/.arcconfig
@@ -0,0 +1,5 @@
+{
+ "repository.callsign": "KHEALTH",
+ "phabricator.uri": "https://devcentral.nasqueron.org",
+ "unit.engine": "PhpunitTestEngine"
+}
diff --git a/.arclint b/.arclint
new file mode 100644
--- /dev/null
+++ b/.arclint
@@ -0,0 +1,32 @@
+{
+ "exclude": [
+ "(^vendor/)"
+ ],
+ "linters": {
+ "chmod": {
+ "type": "chmod"
+ },
+ "filename": {
+ "type": "filename"
+ },
+ "merge-conflict": {
+ "type": "merge-conflict"
+ },
+ "php": {
+ "type": "php",
+ "include": "(\\.php$)"
+ },
+ "phpcs": {
+ "type": "phpcs",
+ "bin": "vendor/bin/phpcs",
+ "phpcs.standard": "phpcs.xml",
+ "include": [
+ "(^src/.*\\.php$)",
+ "(^tests/.*\\.php$)"
+ ]
+ },
+ "spelling": {
+ "type": "spelling"
+ }
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+vendor/
+composer.lock
diff --git a/bin/health b/bin/health
new file mode 100755
--- /dev/null
+++ b/bin/health
@@ -0,0 +1,46 @@
+#!/usr/bin/env php
+
+
+
+
+ src
+ tests
+
diff --git a/src/CLI/HealthCommand.php b/src/CLI/HealthCommand.php
new file mode 100644
--- /dev/null
+++ b/src/CLI/HealthCommand.php
@@ -0,0 +1,45 @@
+argc < 2) {
+ $this->usage();
+ return ExitCode::FAILURE;
+ }
+
+ $class = $this->argv[1];
+
+ if (!class_exists($class)) {
+ $this->display->error("Class not found: " . $class);
+ return ExitCode::ILLEGAL_OPTION;
+ }
+
+ return $this->printReport($class);;
+ }
+
+ public function usage () : void {
+ $usage = sprintf(
+ "Usage: %s ",
+ $this->getCommandName()
+ );
+
+ $this->display->error($usage);
+ }
+
+ private function printReport (string $class) : int {
+ $healthReport = new $class();
+ $report = $healthReport->compile();
+
+ $report->properties["Quux"] = 42;
+ echo $report->render("markdown");
+
+ return ExitCode::fromBoolean($healthReport->isHealthy);
+ }
+
+}
diff --git a/src/Check.php b/src/Check.php
new file mode 100644
--- /dev/null
+++ b/src/Check.php
@@ -0,0 +1,33 @@
+report = new ReportSection(static::class, []);
+ }
+
+ protected function report (string $title, string $text) {
+ $this->report->push($title, $text);
+ }
+
+}
diff --git a/src/HealthReport.php b/src/HealthReport.php
new file mode 100644
--- /dev/null
+++ b/src/HealthReport.php
@@ -0,0 +1,87 @@
+getTitle());
+
+ foreach ($this->getChecks() as $class) {
+ $check = new $class();
+
+ $this->isHealthy &= $check->check();
+ $report->pushIfNotEmpty($check->report);
+ }
+
+ $report->properties = $this->getExtraProperties()
+ + $this->getProperties();
+
+ return $report;
+ }
+
+ /**
+ * @return string The title of the report
+ */
+ public function getTitle () : string {
+ return "Site health";
+ }
+
+ /**
+ * @return array
+ */
+ public function getProperties() : array {
+ return [
+ 'time' => time(),
+ 'hostname' => gethostname(),
+ 'user' => CurrentProcess::getUsername(),
+ 'php_version' => phpversion(),
+ 'healthy' => $this->isHealthy,
+ ];
+ }
+
+ /**
+ * A key/value hashmap of the metadata to add to the report.
+ *
+ * If the key is already defined in the default properties,
+ * the value set in getExtraProperties will be used instead.
+ *
+ * @return array
+ */
+ public function getExtraProperties() : array {
+ return [];
+ }
+
+}